]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '4bdfb0741dbcecd5279a2635c3280726db0604b5' into clippyup
authorPhilipp Krones <hello@philkrones.com>
Sat, 17 Dec 2022 13:12:54 +0000 (14:12 +0100)
committerPhilipp Krones <hello@philkrones.com>
Sat, 17 Dec 2022 13:12:54 +0000 (14:12 +0100)
126 files changed:
1  2 
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/Cargo.toml
src/tools/clippy/book/src/README.md
src/tools/clippy/build.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/almost_complete_range.rs
src/tools/clippy/clippy_lints/src/box_default.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/declared_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/disallowed_macros.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/utils.rs
src/tools/clippy/clippy_lints/src/manual_assert.rs
src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
src/tools/clippy/clippy_lints/src/manual_let_else.rs
src/tools/clippy/clippy_lints/src/manual_retain.rs
src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
src/tools/clippy/clippy_lints/src/operators/identity_op.rs
src/tools/clippy/clippy_lints/src/operators/mod.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
src/tools/clippy/clippy_lints/src/renamed_lints.rs
src/tools/clippy/clippy_lints/src/semicolon_block.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/declare_clippy_lint/Cargo.toml
src/tools/clippy/rust-toolchain
src/tools/clippy/rustc_tools_util/CHANGELOG.md
src/tools/clippy/rustc_tools_util/Cargo.toml
src/tools/clippy/rustc_tools_util/README.md
src/tools/clippy/rustc_tools_util/src/lib.rs
src/tools/clippy/src/driver.rs
src/tools/clippy/src/main.rs
src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/almost_complete_range.fixed
src/tools/clippy/tests/ui/almost_complete_range.rs
src/tools/clippy/tests/ui/almost_complete_range.stderr
src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
src/tools/clippy/tests/ui/cast_lossless_integer.fixed
src/tools/clippy/tests/ui/cast_lossless_integer.rs
src/tools/clippy/tests/ui/collapsible_str_replace.fixed
src/tools/clippy/tests/ui/collapsible_str_replace.rs
src/tools/clippy/tests/ui/collapsible_str_replace.stderr
src/tools/clippy/tests/ui/explicit_counter_loop.rs
src/tools/clippy/tests/ui/from_over_into.fixed
src/tools/clippy/tests/ui/from_over_into.rs
src/tools/clippy/tests/ui/from_over_into.stderr
src/tools/clippy/tests/ui/identity_op.fixed
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/implicit_clone.fixed
src/tools/clippy/tests/ui/implicit_clone.rs
src/tools/clippy/tests/ui/indexing_slicing_index.rs
src/tools/clippy/tests/ui/indexing_slicing_index.stderr
src/tools/clippy/tests/ui/len_zero.fixed
src/tools/clippy/tests/ui/len_zero.rs
src/tools/clippy/tests/ui/len_zero.stderr
src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
src/tools/clippy/tests/ui/manual_assert.rs
src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
src/tools/clippy/tests/ui/manual_is_ascii_check.rs
src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
src/tools/clippy/tests/ui/manual_let_else_match.rs
src/tools/clippy/tests/ui/manual_let_else_match.stderr
src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed
src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs
src/tools/clippy/tests/ui/new_ret_no_self.rs
src/tools/clippy/tests/ui/new_ret_no_self.stderr
src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
src/tools/clippy/tests/ui/rename.fixed
src/tools/clippy/tests/ui/rename.rs
src/tools/clippy/tests/ui/rename.stderr
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
src/tools/clippy/tests/ui/semicolon_inside_block.fixed
src/tools/clippy/tests/ui/semicolon_inside_block.rs
src/tools/clippy/tests/ui/semicolon_inside_block.stderr
src/tools/clippy/tests/ui/semicolon_outside_block.fixed
src/tools/clippy/tests/ui/semicolon_outside_block.rs
src/tools/clippy/tests/ui/semicolon_outside_block.stderr
src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
src/tools/clippy/tests/ui/string_lit_as_bytes.rs
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
src/tools/clippy/tests/ui/unnecessary_to_owned.rs
src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
src/tools/clippy/tests/ui/zero_ptr_no_std.rs
src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
src/tools/clippy/tests/versioncheck.rs
src/tools/clippy/triagebot.toml

index 6448b2d4068deb480aa9484fb082288e7c8b81ca,0000000000000000000000000000000000000000..1bc457a947936b4e35fa9c9cbe8a4f945d1721e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,283 -1,0 +1,276 @@@
-     - name: Install dependencies (Linux-i686)
-       run: |
-         sudo dpkg --add-architecture i386
-         sudo apt-get update
-         sudo apt-get install gcc-multilib libssl-dev:i386 libgit2-dev:i386
-       if: matrix.host == 'i686-unknown-linux-gnu'
 +name: Clippy Test (bors)
 +
 +on:
 +  push:
 +    branches:
 +      - auto
 +      - try
 +
 +env:
 +  RUST_BACKTRACE: 1
 +  CARGO_TARGET_DIR: '${{ github.workspace }}/target'
 +  NO_FMT_TEST: 1
 +  CARGO_INCREMENTAL: 0
 +  CARGO_UNSTABLE_SPARSE_REGISTRY: true
 +
 +defaults:
 +  run:
 +    shell: bash
 +
 +jobs:
 +  changelog:
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: Checkout
 +      uses: actions/checkout@v3.0.2
 +      with:
 +        ref: ${{ github.ref }}
 +
 +    # Run
 +    - name: Check Changelog
 +      run: |
 +        MESSAGE=$(git log --format=%B -n 1)
 +        PR=$(echo "$MESSAGE" | grep -o "#[0-9]*" | head -1 | sed -e 's/^#//')
 +        body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR" | \
 +          python -c "import sys, json; print(json.load(sys.stdin)['body'])")
 +        output=$(grep "^changelog:\s*\S" <<< "$body" | sed "s/changelog:\s*//g") || {
 +          echo "ERROR: PR body must contain 'changelog: ...'"
 +          exit 1
 +        }
 +        if [[ "$output" = "none" ]]; then
 +          echo "WARNING: changelog is 'none'"
 +        else
 +          echo "changelog: $output"
 +        fi
 +      env:
 +        PYTHONIOENCODING: 'utf-8'
 +  base:
 +    needs: changelog
 +    strategy:
 +      matrix:
 +        os: [ubuntu-latest, windows-latest, macos-latest]
 +        host: [x86_64-unknown-linux-gnu, i686-unknown-linux-gnu, x86_64-apple-darwin, x86_64-pc-windows-msvc]
 +        exclude:
 +        - os: ubuntu-latest
 +          host: x86_64-apple-darwin
 +        - os: ubuntu-latest
 +          host: x86_64-pc-windows-msvc
 +        - os: macos-latest
 +          host: x86_64-unknown-linux-gnu
 +        - os: macos-latest
 +          host: i686-unknown-linux-gnu
 +        - os: macos-latest
 +          host: x86_64-pc-windows-msvc
 +        - os: windows-latest
 +          host: x86_64-unknown-linux-gnu
 +        - os: windows-latest
 +          host: i686-unknown-linux-gnu
 +        - os: windows-latest
 +          host: x86_64-apple-darwin
 +
 +    runs-on: ${{ matrix.os }}
 +
 +    # NOTE: If you modify this job, make sure you copy the changes to clippy.yml
 +    steps:
 +    # Setup
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: Checkout
 +      uses: actions/checkout@v3.0.2
 +
 +    - name: Install toolchain
 +      run: rustup show active-toolchain
 +
 +    # Run
 +    - name: Set LD_LIBRARY_PATH (Linux)
 +      if: runner.os == 'Linux'
 +      run: |
 +        SYSROOT=$(rustc --print sysroot)
 +        echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
 +    - name: Link rustc dylib (MacOS)
 +      if: runner.os == 'macOS'
 +      run: |
 +        SYSROOT=$(rustc --print sysroot)
 +        sudo mkdir -p /usr/local/lib
 +        sudo find "${SYSROOT}/lib" -maxdepth 1 -name '*dylib' -exec ln -s {} /usr/local/lib \;
 +    - name: Set PATH (Windows)
 +      if: runner.os == 'Windows'
 +      run: |
 +        SYSROOT=$(rustc --print sysroot)
 +        echo "$SYSROOT/bin" >> $GITHUB_PATH
 +
 +    - name: Build
 +      run: cargo build --features deny-warnings,internal
 +
 +    - name: Test
 +      if: runner.os == 'Linux'
 +      run: cargo test --features deny-warnings,internal
 +
 +    - name: Test
 +      if: runner.os != 'Linux'
 +      run: cargo test --features deny-warnings,internal -- --skip dogfood
 +
 +    - name: Test clippy_lints
 +      run: cargo test --features deny-warnings,internal
 +      working-directory: clippy_lints
 +
 +    - name: Test clippy_utils
 +      run: cargo test --features deny-warnings,internal
 +      working-directory: clippy_utils
 +
 +    - name: Test rustc_tools_util
 +      run: cargo test --features deny-warnings
 +      working-directory: rustc_tools_util
 +
 +    - name: Test clippy_dev
 +      run: cargo test --features deny-warnings
 +      working-directory: clippy_dev
 +
 +    - name: Test clippy-driver
 +      run: bash .github/driver.sh
 +      env:
 +        OS: ${{ runner.os }}
 +
 +  metadata_collection:
 +    needs: changelog
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +     # Setup
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: Checkout
 +      uses: actions/checkout@v3.0.2
 +
 +    - name: Install toolchain
 +      run: rustup show active-toolchain
 +
 +    - name: Test metadata collection
 +      run: cargo collect-metadata
 +
 +  integration_build:
 +    needs: changelog
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +    # Setup
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: Checkout
 +      uses: actions/checkout@v3.0.2
 +
 +    - name: Install toolchain
 +      run: rustup show active-toolchain
 +
 +    # Run
 +    - name: Build Integration Test
 +      run: cargo test --test integration --features integration --no-run
 +
 +    # Upload
 +    - name: Extract Binaries
 +      run: |
 +        DIR=$CARGO_TARGET_DIR/debug
 +        rm $DIR/deps/integration-*.d
 +        mv $DIR/deps/integration-* $DIR/integration
 +        find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
 +        rm -rf $CARGO_TARGET_DIR/release
 +
 +    - name: Upload Binaries
 +      uses: actions/upload-artifact@v1
 +      with:
 +        name: target
 +        path: target
 +
 +  integration:
 +    needs: integration_build
 +    strategy:
 +      fail-fast: false
 +      max-parallel: 6
 +      matrix:
 +        integration:
 +        - 'rust-lang/cargo'
 +        # FIXME: re-enable once fmt_macros is renamed in RLS
 +        # - 'rust-lang/rls'
 +        - 'rust-lang/chalk'
 +        - 'rust-lang/rustfmt'
 +        - 'Marwes/combine'
 +        - 'Geal/nom'
 +        - 'rust-lang/stdarch'
 +        - 'serde-rs/serde'
 +        # FIXME: chrono currently cannot be compiled with `--all-targets`
 +        # - 'chronotope/chrono'
 +        - 'hyperium/hyper'
 +        - 'rust-random/rand'
 +        - 'rust-lang/futures-rs'
 +        - 'rust-itertools/itertools'
 +        - 'rust-lang-nursery/failure'
 +        - 'rust-lang/log'
 +
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +    # Setup
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: Checkout
 +      uses: actions/checkout@v3.0.2
 +
 +    - name: Install toolchain
 +      run: rustup show active-toolchain
 +
 +    # Download
 +    - name: Download target dir
 +      uses: actions/download-artifact@v1
 +      with:
 +        name: target
 +        path: target
 +
 +    - name: Make Binaries Executable
 +      run: chmod +x $CARGO_TARGET_DIR/debug/*
 +
 +    # Run
 +    - name: Test ${{ matrix.integration }}
 +      run: |
 +        RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \
 +          $CARGO_TARGET_DIR/debug/integration
 +      env:
 +        INTEGRATION: ${{ matrix.integration }}
 +
 +  # These jobs doesn't actually test anything, but they're only used to tell
 +  # bors the build completed, as there is no practical way to detect when a
 +  # workflow is successful listening to webhooks only.
 +  #
 +  # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
 +
 +  end-success:
 +    name: bors test finished
 +    if: github.event.pusher.name == 'bors' && success()
 +    runs-on: ubuntu-latest
 +    needs: [changelog, base, metadata_collection, integration_build, integration]
 +
 +    steps:
 +      - name: Mark the job as successful
 +        run: exit 0
 +
 +  end-failure:
 +    name: bors test finished
 +    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
 +    runs-on: ubuntu-latest
 +    needs: [changelog, base, metadata_collection, integration_build, integration]
 +
 +    steps:
 +      - name: Mark the job as a failure
 +        run: exit 1
index 23912bb3ed6b16aea9a4ce27ad1cd5a1a2f50661,0000000000000000000000000000000000000000..903ee938d9d2d2f73e535c3b05eff4be2b628b49
mode 100644,000000..100644
--- /dev/null
@@@ -1,4522 -1,0 +1,4695 @@@
- [b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
 +# Changelog
 +
 +All notable changes to this project will be documented in this file.
 +See [Changelog Update](book/src/development/infrastructure/changelog_update.md) if you want to update this
 +document.
 +
 +## Unreleased / Beta / In Rust Nightly
 +
- Current stable, released 2022-11-03
++[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
++
++## Rust 1.66
++
++Current stable, released 2022-12-15
++
++[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
++
++### New Lints
++
++* [`manual_clamp`]
++  [#9484](https://github.com/rust-lang/rust-clippy/pull/9484)
++* [`missing_trait_methods`]
++  [#9670](https://github.com/rust-lang/rust-clippy/pull/9670)
++* [`unused_format_specs`]
++  [#9637](https://github.com/rust-lang/rust-clippy/pull/9637)
++* [`iter_kv_map`]
++  [#9409](https://github.com/rust-lang/rust-clippy/pull/9409)
++* [`manual_filter`]
++  [#9451](https://github.com/rust-lang/rust-clippy/pull/9451)
++* [`box_default`]
++  [#9511](https://github.com/rust-lang/rust-clippy/pull/9511)
++* [`implicit_saturating_add`]
++  [#9549](https://github.com/rust-lang/rust-clippy/pull/9549)
++* [`as_ptr_cast_mut`]
++  [#9572](https://github.com/rust-lang/rust-clippy/pull/9572)
++* [`disallowed_macros`]
++  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
++* [`partial_pub_fields`]
++  [#9658](https://github.com/rust-lang/rust-clippy/pull/9658)
++* [`uninlined_format_args`]
++  [#9233](https://github.com/rust-lang/rust-clippy/pull/9233)
++* [`cast_nan_to_int`]
++  [#9617](https://github.com/rust-lang/rust-clippy/pull/9617)
++
++### Moves and Deprecations
++
++* `positional_named_format_parameters` was uplifted to rustc under the new name
++  `named_arguments_used_positionally`
++  [#8518](https://github.com/rust-lang/rust-clippy/pull/8518)
++* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default)
++  [#9584](https://github.com/rust-lang/rust-clippy/pull/9584)
++* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default)
++  [#9536](https://github.com/rust-lang/rust-clippy/pull/9536)
++
++### Enhancements
++
++* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config
++  [#9471](https://github.com/rust-lang/rust-clippy/pull/9471)
++* [`suboptimal_flops`]: Now supports multiplication and subtraction operations
++  [#9581](https://github.com/rust-lang/rust-clippy/pull/9581)
++* [`arithmetic_side_effects`]: Now detects cases with literals behind references
++  [#9587](https://github.com/rust-lang/rust-clippy/pull/9587)
++* [`upper_case_acronyms`]: Now also checks enum names
++  [#9580](https://github.com/rust-lang/rust-clippy/pull/9580)
++* [`needless_borrowed_reference`]: Now lints nested patterns
++  [#9573](https://github.com/rust-lang/rust-clippy/pull/9573)
++* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions
++  [#9576](https://github.com/rust-lang/rust-clippy/pull/9576)
++* [`arithmetic_side_effects`]: Now detects operations with custom types
++  [#9559](https://github.com/rust-lang/rust-clippy/pull/9559)
++* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros
++  with the same path
++  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
++* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account
++  [#9475](https://github.com/rust-lang/rust-clippy/pull/9475)
++* [`bool_to_int_with_if`]: Now detects the inverse if case
++  [#9476](https://github.com/rust-lang/rust-clippy/pull/9476)
++
++### False Positive Fixes
++
++* [`arithmetic_side_effects`]: Now allows operations that can't overflow
++  [#9474](https://github.com/rust-lang/rust-clippy/pull/9474)
++* [`unnecessary_lazy_evaluations`]: No longer lints in external macros
++  [#9486](https://github.com/rust-lang/rust-clippy/pull/9486)
++* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference
++  [#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
++* [`almost_complete_letter_range`]: No longer lints in external macros
++  [#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
++* [`drop_copy`]: No longer lints on idiomatic cases in match arms 
++  [#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
++* [`question_mark`]: No longer lints in const context
++  [#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
++* [`collapsible_if`]: Suggestion now work in macros
++  [#9410](https://github.com/rust-lang/rust-clippy/pull/9410)
++* [`std_instead_of_core`]: No longer triggers on unstable modules
++  [#9545](https://github.com/rust-lang/rust-clippy/pull/9545)
++* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function
++  [#9465](https://github.com/rust-lang/rust-clippy/pull/9465)
++* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`]
++  [#9593](https://github.com/rust-lang/rust-clippy/pull/9593)
++* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has
++  custom `Drop` implementation
++  [#9551](https://github.com/rust-lang/rust-clippy/pull/9551)
++* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats
++  [#9609](https://github.com/rust-lang/rust-clippy/pull/9609)
++* [`use_self`]: No longer lints in proc macros
++  [#9454](https://github.com/rust-lang/rust-clippy/pull/9454)
++* [`never_loop`]: Now takes `let ... else` statements into consideration.
++  [#9496](https://github.com/rust-lang/rust-clippy/pull/9496)
++* [`default_numeric_fallback`]: Now ignores constants
++  [#9636](https://github.com/rust-lang/rust-clippy/pull/9636)
++* [`uninit_vec`]: No longer lints `Vec::set_len(0)`
++  [#9519](https://github.com/rust-lang/rust-clippy/pull/9519)
++* [`arithmetic_side_effects`]: Now ignores references to integer types
++  [#9507](https://github.com/rust-lang/rust-clippy/pull/9507)
++* [`large_stack_arrays`]: No longer lints inside static items
++  [#9466](https://github.com/rust-lang/rust-clippy/pull/9466)
++* [`ref_option_ref`]: No longer lints if the inner reference is mutable
++  [#9684](https://github.com/rust-lang/rust-clippy/pull/9684)
++* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object
++  [#9645](https://github.com/rust-lang/rust-clippy/pull/9645)
++* [`should_implement_trait`]: Now also works for `default` methods
++  [#9546](https://github.com/rust-lang/rust-clippy/pull/9546)
++
++### Suggestion Fixes/Improvements
++
++* [`derivable_impls`]: The suggestion is now machine applicable
++  [#9429](https://github.com/rust-lang/rust-clippy/pull/9429)
++* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better
++  [#9601](https://github.com/rust-lang/rust-clippy/pull/9601)
++* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible
++  [#9652](https://github.com/rust-lang/rust-clippy/pull/9652)
++* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes
++  [#9633](https://github.com/rust-lang/rust-clippy/pull/9633)
++* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores
++  comments after the macro call.
++  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
++* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables
++  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
++* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer
++  replace brackets inside the macro argument.
++  [#9499](https://github.com/rust-lang/rust-clippy/pull/9499)
++* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations
++  [#9649](https://github.com/rust-lang/rust-clippy/pull/9649)
++* [`needless_return`]: The automatic suggestion now removes all required semicolons
++  [#9497](https://github.com/rust-lang/rust-clippy/pull/9497)
++* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values
++  [#9590](https://github.com/rust-lang/rust-clippy/pull/9590)
++* [`manual_assert`]: The suggestion now preserves comments
++  [#9479](https://github.com/rust-lang/rust-clippy/pull/9479)
++* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to
++  avoid semantic changes
++  [#9634](https://github.com/rust-lang/rust-clippy/pull/9634)
++* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the
++  `assert!` is not in a statement.
++  [#9453](https://github.com/rust-lang/rust-clippy/pull/9453)
++* [`nonminimal_bool`]: The suggestion no longer expands macros
++  [#9457](https://github.com/rust-lang/rust-clippy/pull/9457)
++* [`collapsible_match`]: Now specifies field names, when a struct is destructed
++  [#9685](https://github.com/rust-lang/rust-clippy/pull/9685)
++* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers
++  [#9577](https://github.com/rust-lang/rust-clippy/pull/9577)
++* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments
++  [#9556](https://github.com/rust-lang/rust-clippy/pull/9556)
++
++### ICE Fixes
++
++* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
++  [#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
++* [`manual_range_contains`]: No longer ICEs on values behind references
++  [#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
++* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
++  [#9531](https://github.com/rust-lang/rust-clippy/pull/9531)
++* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types
++  [#9539](https://github.com/rust-lang/rust-clippy/pull/9539)
++
++### Others
++
++* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will
++  not be published as part of this changelog)
 +
 +## Rust 1.65
 +
++Released 2022-11-03
 +
 +[3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
 +
 +### Important Changes
 +
 +* Clippy now has an `--explain <LINT>` command to show the lint description in the console
 +  [#8952](https://github.com/rust-lang/rust-clippy/pull/8952)
 +
 +### New Lints
 +
 +* [`unused_peekable`]
 +  [#9258](https://github.com/rust-lang/rust-clippy/pull/9258)
 +* [`collapsible_str_replace`]
 +  [#9269](https://github.com/rust-lang/rust-clippy/pull/9269)
 +* [`manual_string_new`]
 +  [#9295](https://github.com/rust-lang/rust-clippy/pull/9295)
 +* [`iter_on_empty_collections`]
 +  [#9187](https://github.com/rust-lang/rust-clippy/pull/9187)
 +* [`iter_on_single_items`]
 +  [#9187](https://github.com/rust-lang/rust-clippy/pull/9187)
 +* [`bool_to_int_with_if`]
 +  [#9412](https://github.com/rust-lang/rust-clippy/pull/9412)
 +* [`multi_assignments`]
 +  [#9379](https://github.com/rust-lang/rust-clippy/pull/9379)
 +* [`result_large_err`]
 +  [#9373](https://github.com/rust-lang/rust-clippy/pull/9373)
 +* [`partialeq_to_none`]
 +  [#9288](https://github.com/rust-lang/rust-clippy/pull/9288)
 +* [`suspicious_to_owned`]
 +  [#8984](https://github.com/rust-lang/rust-clippy/pull/8984)
 +* [`cast_slice_from_raw_parts`]
 +  [#9247](https://github.com/rust-lang/rust-clippy/pull/9247)
 +* [`manual_instant_elapsed`]
 +  [#9264](https://github.com/rust-lang/rust-clippy/pull/9264)
 +
 +### Moves and Deprecations
 +
 +* Moved [`significant_drop_in_scrutinee`] to `nursery` (now allow-by-default)
 +  [#9302](https://github.com/rust-lang/rust-clippy/pull/9302)
 +* Rename `logic_bug` to [`overly_complex_bool_expr`]
 +  [#9306](https://github.com/rust-lang/rust-clippy/pull/9306)
 +* Rename `arithmetic` to [`arithmetic_side_effects`]
 +  [#9443](https://github.com/rust-lang/rust-clippy/pull/9443)
 +* Moved [`only_used_in_recursion`] to complexity (now warn-by-default)
 +  [#8804](https://github.com/rust-lang/rust-clippy/pull/8804)
 +* Moved [`assertions_on_result_states`] to restriction (now allow-by-default)
 +  [#9273](https://github.com/rust-lang/rust-clippy/pull/9273)
 +* Renamed `blacklisted_name` to [`disallowed_names`]
 +  [#8974](https://github.com/rust-lang/rust-clippy/pull/8974)
 +
 +### Enhancements
 +
 +* [`option_if_let_else`]: Now also checks for match expressions
 +  [#8696](https://github.com/rust-lang/rust-clippy/pull/8696)
 +* [`explicit_auto_deref`]: Now lints on implicit returns in closures
 +  [#9126](https://github.com/rust-lang/rust-clippy/pull/9126)
 +* [`needless_borrow`]: Now considers trait implementations
 +  [#9136](https://github.com/rust-lang/rust-clippy/pull/9136)
 +* [`suboptimal_flops`], [`imprecise_flops`]: Now lint on constant expressions
 +  [#9404](https://github.com/rust-lang/rust-clippy/pull/9404)
 +* [`if_let_mutex`]: Now detects mutex behind references and warns about deadlocks
 +  [#9318](https://github.com/rust-lang/rust-clippy/pull/9318)
 +
 +### False Positive Fixes
 +
 +* [`unit_arg`] [`default_trait_access`] [`missing_docs_in_private_items`]: No longer
 +  trigger in code generated from proc-macros
 +  [#8694](https://github.com/rust-lang/rust-clippy/pull/8694)
 +* [`unwrap_used`]: Now lints uses of `unwrap_err`
 +  [#9338](https://github.com/rust-lang/rust-clippy/pull/9338)
 +* [`expect_used`]: Now lints uses of `expect_err`
 +  [#9338](https://github.com/rust-lang/rust-clippy/pull/9338)
 +* [`transmute_undefined_repr`]: Now longer lints if the first field is compatible
 +  with the other type
 +  [#9287](https://github.com/rust-lang/rust-clippy/pull/9287)
 +* [`unnecessary_to_owned`]: No longer lints, if type change cased errors in
 +  the caller function
 +  [#9424](https://github.com/rust-lang/rust-clippy/pull/9424)
 +* [`match_like_matches_macro`]: No longer lints, if there are comments inside the
 +  match expression
 +  [#9276](https://github.com/rust-lang/rust-clippy/pull/9276)
 +* [`partialeq_to_none`]: No longer trigger in code generated from macros
 +  [#9389](https://github.com/rust-lang/rust-clippy/pull/9389)
 +* [`arithmetic_side_effects`]: No longer lints expressions that only use literals
 +  [#9365](https://github.com/rust-lang/rust-clippy/pull/9365)
 +* [`explicit_auto_deref`]: Now ignores references on block expressions when the type
 +  is `Sized`, on `dyn Trait` returns and when the suggestion is non-trivial
 +  [#9126](https://github.com/rust-lang/rust-clippy/pull/9126)
 +* [`trait_duplication_in_bounds`]: Now better tracks bounds to avoid false positives
 +  [#9167](https://github.com/rust-lang/rust-clippy/pull/9167)
 +* [`format_in_format_args`]: Now suggests cases where the result is formatted again
 +  [#9349](https://github.com/rust-lang/rust-clippy/pull/9349)
 +* [`only_used_in_recursion`]: No longer lints on function without recursions and
 +  takes external functions into account
 +  [#8804](https://github.com/rust-lang/rust-clippy/pull/8804)
 +* [`missing_const_for_fn`]: No longer lints in proc-macros
 +  [#9308](https://github.com/rust-lang/rust-clippy/pull/9308)
 +* [`non_ascii_literal`]: Allow non-ascii comments in tests and make sure `#[allow]`
 +  attributes work in tests
 +  [#9327](https://github.com/rust-lang/rust-clippy/pull/9327)
 +* [`question_mark`]: No longer lint `if let`s with subpatterns
 +  [#9348](https://github.com/rust-lang/rust-clippy/pull/9348)
 +* [`needless_collect`]: No longer lints in loops
 +  [#8992](https://github.com/rust-lang/rust-clippy/pull/8992)
 +* [`mut_mutex_lock`]: No longer lints if the mutex is behind an immutable reference
 +  [#9418](https://github.com/rust-lang/rust-clippy/pull/9418)
 +* [`needless_return`]: Now ignores returns with arguments
 +  [#9381](https://github.com/rust-lang/rust-clippy/pull/9381)
 +* [`range_plus_one`], [`range_minus_one`]: Now ignores code with macros
 +  [#9446](https://github.com/rust-lang/rust-clippy/pull/9446)
 +* [`assertions_on_result_states`]: No longer lints on the unit type
 +  [#9273](https://github.com/rust-lang/rust-clippy/pull/9273)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unwrap_or_else_default`]: Now suggests `unwrap_or_default()` for empty strings
 +  [#9421](https://github.com/rust-lang/rust-clippy/pull/9421)
 +* [`if_then_some_else_none`]: Now also suggests `bool::then_some`
 +  [#9289](https://github.com/rust-lang/rust-clippy/pull/9289)
 +* [`redundant_closure_call`]: The suggestion now works for async closures
 +  [#9053](https://github.com/rust-lang/rust-clippy/pull/9053)
 +* [`suboptimal_flops`]: Now suggests parenthesis when they are required
 +  [#9394](https://github.com/rust-lang/rust-clippy/pull/9394)
 +* [`case_sensitive_file_extension_comparisons`]: Now suggests `map_or(..)` instead of `map(..).unwrap_or`
 +  [#9341](https://github.com/rust-lang/rust-clippy/pull/9341)
 +* Deprecated configuration values can now be updated automatically
 +  [#9252](https://github.com/rust-lang/rust-clippy/pull/9252)
 +* [`or_fun_call`]: Now suggest `Entry::or_default` for `Entry::or_insert(Default::default())`
 +  [#9342](https://github.com/rust-lang/rust-clippy/pull/9342)
 +* [`unwrap_used`]: Only suggests `expect` if [`expect_used`] is allowed
 +  [#9223](https://github.com/rust-lang/rust-clippy/pull/9223)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`useless_format`] for literals
 +  [#9406](https://github.com/rust-lang/rust-clippy/pull/9406)
 +* Fix infinite loop in [`vec_init_then_push`]
 +  [#9441](https://github.com/rust-lang/rust-clippy/pull/9441)
 +* Fix ICE when reading literals with weird proc-macro spans
 +  [#9303](https://github.com/rust-lang/rust-clippy/pull/9303)
 +
 +## Rust 1.64
 +
 +Released 2022-09-22
 +
 +[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc)
 +
 +### New Lints
 +
 +* [`arithmetic_side_effects`]
 +  [#9130](https://github.com/rust-lang/rust-clippy/pull/9130)
 +* [`invalid_utf8_in_unchecked`]
 +  [#9105](https://github.com/rust-lang/rust-clippy/pull/9105)
 +* [`assertions_on_result_states`]
 +  [#9225](https://github.com/rust-lang/rust-clippy/pull/9225)
 +* [`manual_find`]
 +  [#8649](https://github.com/rust-lang/rust-clippy/pull/8649)
 +* [`manual_retain`]
 +  [#8972](https://github.com/rust-lang/rust-clippy/pull/8972)
 +* [`default_instead_of_iter_empty`]
 +  [#8989](https://github.com/rust-lang/rust-clippy/pull/8989)
 +* [`manual_rem_euclid`]
 +  [#9031](https://github.com/rust-lang/rust-clippy/pull/9031)
 +* [`obfuscated_if_else`]
 +  [#9148](https://github.com/rust-lang/rust-clippy/pull/9148)
 +* [`std_instead_of_core`]
 +  [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
 +* [`std_instead_of_alloc`]
 +  [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
 +* [`alloc_instead_of_core`]
 +  [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
 +* [`explicit_auto_deref`]
 +  [#8355](https://github.com/rust-lang/rust-clippy/pull/8355)
 +
 +
 +### Moves and Deprecations
 +
 +* Moved [`format_push_string`] to `restriction` (now allow-by-default)
 +  [#9161](https://github.com/rust-lang/rust-clippy/pull/9161)
 +
 +### Enhancements
 +
 +* [`significant_drop_in_scrutinee`]: Now gives more context in the lint message
 +  [#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
 +* [`single_match`], [`single_match_else`]: Now catches more `Option` cases
 +  [#8985](https://github.com/rust-lang/rust-clippy/pull/8985)
 +* [`unused_async`]: Now works for async methods
 +  [#9025](https://github.com/rust-lang/rust-clippy/pull/9025)
 +* [`manual_filter_map`], [`manual_find_map`]: Now lint more expressions
 +  [#8958](https://github.com/rust-lang/rust-clippy/pull/8958)
 +* [`question_mark`]: Now works for simple `if let` expressions
 +  [#8356](https://github.com/rust-lang/rust-clippy/pull/8356)
 +* [`undocumented_unsafe_blocks`]: Now finds comments before the start of closures
 +  [#9117](https://github.com/rust-lang/rust-clippy/pull/9117)
 +* [`trait_duplication_in_bounds`]: Now catches duplicate bounds in where clauses
 +  [#8703](https://github.com/rust-lang/rust-clippy/pull/8703)
 +* [`shadow_reuse`], [`shadow_same`], [`shadow_unrelated`]: Now lint in const blocks
 +  [#9124](https://github.com/rust-lang/rust-clippy/pull/9124)
 +* [`slow_vector_initialization`]: Now detects cases with `vec.capacity()`
 +  [#8953](https://github.com/rust-lang/rust-clippy/pull/8953)
 +* [`unused_self`]: Now respects the `avoid-breaking-exported-api` config option
 +  [#9199](https://github.com/rust-lang/rust-clippy/pull/9199)
 +* [`box_collection`]: Now supports all std collections
 +  [#9170](https://github.com/rust-lang/rust-clippy/pull/9170)
 +
 +### False Positive Fixes
 +
 +* [`significant_drop_in_scrutinee`]: Now ignores calls to `IntoIterator::into_iter`
 +  [#9140](https://github.com/rust-lang/rust-clippy/pull/9140)
 +* [`while_let_loop`]: Now ignores cases when the significant drop order would change
 +  [#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
 +* [`branches_sharing_code`]: Now ignores cases where moved variables have a significant
 +  drop or variable modifications can affect the conditions
 +  [#9138](https://github.com/rust-lang/rust-clippy/pull/9138)
 +* [`let_underscore_lock`]: Now ignores bindings that aren't locked
 +  [#8990](https://github.com/rust-lang/rust-clippy/pull/8990)
 +* [`trivially_copy_pass_by_ref`]: Now tracks lifetimes and ignores cases where unsafe
 +  pointers are used
 +  [#8639](https://github.com/rust-lang/rust-clippy/pull/8639)
 +* [`let_unit_value`]: No longer ignores `#[allow]` attributes on the value
 +  [#9082](https://github.com/rust-lang/rust-clippy/pull/9082)
 +* [`declare_interior_mutable_const`]: Now ignores the `thread_local!` macro
 +  [#9015](https://github.com/rust-lang/rust-clippy/pull/9015)
 +* [`if_same_then_else`]: Now ignores branches with `todo!` and `unimplemented!`
 +  [#9006](https://github.com/rust-lang/rust-clippy/pull/9006)
 +* [`enum_variant_names`]: Now ignores names with `_` prefixes
 +  [#9032](https://github.com/rust-lang/rust-clippy/pull/9032)
 +* [`let_unit_value`]: Now ignores cases, where the unit type is manually specified
 +  [#9056](https://github.com/rust-lang/rust-clippy/pull/9056)
 +* [`match_same_arms`]: Now ignores branches with `todo!`
 +  [#9207](https://github.com/rust-lang/rust-clippy/pull/9207)
 +* [`assign_op_pattern`]: Ignores cases that break borrowing rules
 +  [#9214](https://github.com/rust-lang/rust-clippy/pull/9214)
 +* [`extra_unused_lifetimes`]: No longer triggers in derive macros
 +  [#9037](https://github.com/rust-lang/rust-clippy/pull/9037)
 +* [`mismatching_type_param_order`]: Now ignores complicated generic parameters
 +  [#9146](https://github.com/rust-lang/rust-clippy/pull/9146)
 +* [`equatable_if_let`]: No longer lints in macros
 +  [#9074](https://github.com/rust-lang/rust-clippy/pull/9074)
 +* [`new_without_default`]: Now ignores generics and lifetime parameters on `fn new`
 +  [#9115](https://github.com/rust-lang/rust-clippy/pull/9115)
 +* [`needless_borrow`]: Now ignores cases that result in the execution of different traits
 +  [#9096](https://github.com/rust-lang/rust-clippy/pull/9096)
 +* [`declare_interior_mutable_const`]: No longer triggers in thread-local initializers
 +  [#9246](https://github.com/rust-lang/rust-clippy/pull/9246)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`type_repetition_in_bounds`]: The suggestion now works with maybe bounds
 +  [#9132](https://github.com/rust-lang/rust-clippy/pull/9132)
 +* [`transmute_ptr_to_ref`]: Now suggests `pointer::cast` when possible
 +  [#8939](https://github.com/rust-lang/rust-clippy/pull/8939)
 +* [`useless_format`]: Now suggests the correct variable name
 +  [#9237](https://github.com/rust-lang/rust-clippy/pull/9237)
 +* [`or_fun_call`]: The lint emission will now only span over the `unwrap_or` call
 +  [#9144](https://github.com/rust-lang/rust-clippy/pull/9144)
 +* [`neg_multiply`]: Now suggests adding parentheses around suggestion if needed
 +  [#9026](https://github.com/rust-lang/rust-clippy/pull/9026)
 +* [`unnecessary_lazy_evaluations`]: Now suggest for `bool::then_some` for lazy evaluation
 +  [#9099](https://github.com/rust-lang/rust-clippy/pull/9099)
 +* [`manual_flatten`]: Improved message for long code snippets
 +  [#9156](https://github.com/rust-lang/rust-clippy/pull/9156)
 +* [`explicit_counter_loop`]: The suggestion is now machine applicable
 +  [#9149](https://github.com/rust-lang/rust-clippy/pull/9149)
 +* [`needless_borrow`]: Now keeps parentheses around fields, when needed
 +  [#9210](https://github.com/rust-lang/rust-clippy/pull/9210)
 +* [`while_let_on_iterator`]: The suggestion now works in `FnOnce` closures
 +  [#9134](https://github.com/rust-lang/rust-clippy/pull/9134)
 +
 +### ICE Fixes
 +
 +* Fix ICEs related to `#![feature(generic_const_exprs)]` usage
 +  [#9241](https://github.com/rust-lang/rust-clippy/pull/9241)
 +* Fix ICEs related to reference lints
 +  [#9093](https://github.com/rust-lang/rust-clippy/pull/9093)
 +* [`question_mark`]: Fix ICE on zero field tuple structs
 +  [#9244](https://github.com/rust-lang/rust-clippy/pull/9244)
 +
 +### Documentation Improvements
 +
 +* [`needless_option_take`]: Now includes a "What it does" and "Why is this bad?" section.
 +  [#9022](https://github.com/rust-lang/rust-clippy/pull/9022)
 +
 +### Others
 +
 +* Using `--cap-lints=allow` and only `--force-warn`ing some will now work with Clippy's driver
 +  [#9036](https://github.com/rust-lang/rust-clippy/pull/9036)
 +* Clippy now tries to read the `rust-version` from `Cargo.toml` to identify the
 +  minimum supported rust version
 +  [#8774](https://github.com/rust-lang/rust-clippy/pull/8774)
 +
 +## Rust 1.63
 +
 +Released 2022-08-11
 +
 +[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0)
 +
 +### New Lints
 +
 +* [`borrow_deref_ref`]
 +  [#7930](https://github.com/rust-lang/rust-clippy/pull/7930)
 +* [`doc_link_with_quotes`]
 +  [#8385](https://github.com/rust-lang/rust-clippy/pull/8385)
 +* [`no_effect_replace`]
 +  [#8754](https://github.com/rust-lang/rust-clippy/pull/8754)
 +* [`rc_clone_in_vec_init`]
 +  [#8769](https://github.com/rust-lang/rust-clippy/pull/8769)
 +* [`derive_partial_eq_without_eq`]
 +  [#8796](https://github.com/rust-lang/rust-clippy/pull/8796)
 +* [`mismatching_type_param_order`]
 +  [#8831](https://github.com/rust-lang/rust-clippy/pull/8831)
 +* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832)
 +* [`unused_rounding`]
 +  [#8866](https://github.com/rust-lang/rust-clippy/pull/8866)
 +* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882)
 +* [`swap_ptr_to_ref`]
 +  [#8916](https://github.com/rust-lang/rust-clippy/pull/8916)
 +* [`almost_complete_letter_range`]
 +  [#8918](https://github.com/rust-lang/rust-clippy/pull/8918)
 +* [`needless_parens_on_range_literals`]
 +  [#8933](https://github.com/rust-lang/rust-clippy/pull/8933)
 +* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934)
 +
 +### Moves and Deprecations
 +
 +* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to
 +  `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621)
 +
 +### Enhancements
 +
 +* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations
 +  [#8761](https://github.com/rust-lang/rust-clippy/pull/8761)
 +* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros
 +  [#8790](https://github.com/rust-lang/rust-clippy/pull/8790)
 +* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests`
 +  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
 +* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests`
 +  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
 +* [`disallowed_methods`]: Now also lints indirect usages
 +  [#8852](https://github.com/rust-lang/rust-clippy/pull/8852)
 +* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice
 +  [#8862](https://github.com/rust-lang/rust-clippy/pull/8862)
 +* [`manual_range_contains`]: Now also lints on chains of `&&` and `||`
 +  [#8884](https://github.com/rust-lang/rust-clippy/pull/8884)
 +* [`rc_clone_in_vec_init`]: Now also lints on `Weak`
 +  [#8885](https://github.com/rust-lang/rust-clippy/pull/8885)
 +* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option
 +  [#8897](https://github.com/rust-lang/rust-clippy/pull/8897)
 +* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns
 +  [#8899](https://github.com/rust-lang/rust-clippy/pull/8899)
 +* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex
 +  method chains inside `map`
 +  [#8930](https://github.com/rust-lang/rust-clippy/pull/8930)
 +* [`needless_return`]: Now also lints on macro expressions in return statements
 +  [#8932](https://github.com/rust-lang/rust-clippy/pull/8932)
 +* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config
 +  should extend the default and not replace it
 +  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
 +* [`disallowed_names`]: Users can now indicate, that the `disallowed-names`
 +  config should extend the default and not replace it
 +  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
 +* [`never_loop`]: Now checks for `continue` in struct expression
 +  [#9002](https://github.com/rust-lang/rust-clippy/pull/9002)
 +
 +### False Positive Fixes
 +
 +* [`useless_transmute`]: No longer lints on types with erased regions
 +  [#8564](https://github.com/rust-lang/rust-clippy/pull/8564)
 +* [`vec_init_then_push`]: No longer lints when further extended
 +  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
 +* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types
 +  [#8807](https://github.com/rust-lang/rust-clippy/pull/8807)
 +* [`redundant_allocation`]: No longer lints on fat pointers that would become
 +  thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
 +* [`derive_partial_eq_without_eq`]:
 +    * Handle differing predicates applied by `#[derive(PartialEq)]` and
 +      `#[derive(Eq)]`
 +      [#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
 +    * No longer lints on non-public types and better handles generics
 +      [#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
 +* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
 +  string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
 +* [`branches_sharing_code`]: No longer lints when using different binding names
 +  [#8901](https://github.com/rust-lang/rust-clippy/pull/8901)
 +* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await`
 +  desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
 +* [`checked_conversions`]: No longer lints in `const` contexts
 +  [#8907](https://github.com/rust-lang/rust-clippy/pull/8907)
 +* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when
 +  `T::Item` doesn't implement `IntoIterator`
 +  [#8960](https://github.com/rust-lang/rust-clippy/pull/8960)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible
 +  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
 +* [`manual_range_contains`]: Fix suggestion for integers with different signs
 +  [#8763](https://github.com/rust-lang/rust-clippy/pull/8763)
 +* [`identity_op`]: Add parenthesis to suggestions where required
 +  [#8786](https://github.com/rust-lang/rust-clippy/pull/8786)
 +* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64`
 +  [#8778](https://github.com/rust-lang/rust-clippy/pull/8778)
 +* [`rc_clone_in_vec_init`]: Add suggestion
 +  [#8814](https://github.com/rust-lang/rust-clippy/pull/8814)
 +* The "unknown field" error messages for config files now wraps the field names
 +  [#8823](https://github.com/rust-lang/rust-clippy/pull/8823)
 +* [`cast_abs_to_unsigned`]: Do not remove cast if it's required
 +  [#8876](https://github.com/rust-lang/rust-clippy/pull/8876)
 +* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not
 +  references and not trivially clone-able
 +  [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
 +* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`,
 +  `iter_mut()` or `into_iter()`
 +  [#8941](https://github.com/rust-lang/rust-clippy/pull/8941)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type
 +  [#8835](https://github.com/rust-lang/rust-clippy/pull/8835)
 +* Fix ICEs on callable `static`/`const`s
 +  [#8896](https://github.com/rust-lang/rust-clippy/pull/8896)
 +* [`needless_late_init`]
 +  [#8912](https://github.com/rust-lang/rust-clippy/pull/8912)
 +* Fix ICE in shadow lints
 +  [#8913](https://github.com/rust-lang/rust-clippy/pull/8913)
 +
 +### Documentation Improvements
 +
 +* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now!
 +  [#7359](https://github.com/rust-lang/rust-clippy/pull/7359)
 +* Add a *copy lint name*-button to Clippy's lint list
 +  [#8839](https://github.com/rust-lang/rust-clippy/pull/8839)
 +* Display past names of renamed lints on Clippy's lint list
 +  [#8843](https://github.com/rust-lang/rust-clippy/pull/8843)
 +* Add the ability to show the lint output in the lint list
 +  [#8947](https://github.com/rust-lang/rust-clippy/pull/8947)
 +
 +## Rust 1.62
 +
 +Released 2022-06-30
 +
 +[d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b)
 +
 +### New Lints
 +
 +* [`large_include_file`]
 +  [#8727](https://github.com/rust-lang/rust-clippy/pull/8727)
 +* [`cast_abs_to_unsigned`]
 +  [#8635](https://github.com/rust-lang/rust-clippy/pull/8635)
 +* [`err_expect`]
 +  [#8606](https://github.com/rust-lang/rust-clippy/pull/8606)
 +* [`unnecessary_owned_empty_strings`]
 +  [#8660](https://github.com/rust-lang/rust-clippy/pull/8660)
 +* [`empty_structs_with_brackets`]
 +  [#8594](https://github.com/rust-lang/rust-clippy/pull/8594)
 +* [`crate_in_macro_def`]
 +  [#8576](https://github.com/rust-lang/rust-clippy/pull/8576)
 +* [`needless_option_take`]
 +  [#8665](https://github.com/rust-lang/rust-clippy/pull/8665)
 +* [`bytes_count_to_len`]
 +  [#8711](https://github.com/rust-lang/rust-clippy/pull/8711)
 +* [`is_digit_ascii_radix`]
 +  [#8624](https://github.com/rust-lang/rust-clippy/pull/8624)
 +* [`await_holding_invalid_type`]
 +  [#8707](https://github.com/rust-lang/rust-clippy/pull/8707)
 +* [`trim_split_whitespace`]
 +  [#8575](https://github.com/rust-lang/rust-clippy/pull/8575)
 +* [`pub_use`]
 +  [#8670](https://github.com/rust-lang/rust-clippy/pull/8670)
 +* [`format_push_string`]
 +  [#8626](https://github.com/rust-lang/rust-clippy/pull/8626)
 +* [`empty_drop`]
 +  [#8571](https://github.com/rust-lang/rust-clippy/pull/8571)
 +* [`drop_non_drop`]
 +  [#8630](https://github.com/rust-lang/rust-clippy/pull/8630)
 +* [`forget_non_drop`]
 +  [#8630](https://github.com/rust-lang/rust-clippy/pull/8630)
 +
 +### Moves and Deprecations
 +
 +* Move [`only_used_in_recursion`] to `nursery` (now allow-by-default)
 +  [#8783](https://github.com/rust-lang/rust-clippy/pull/8783)
 +* Move [`stable_sort_primitive`] to `pedantic` (now allow-by-default)
 +  [#8716](https://github.com/rust-lang/rust-clippy/pull/8716)
 +
 +### Enhancements
 +
 +* Remove overlap between [`manual_split_once`] and [`needless_splitn`]
 +  [#8631](https://github.com/rust-lang/rust-clippy/pull/8631)
 +* [`map_identity`]: Now checks for needless `map_err`
 +  [#8487](https://github.com/rust-lang/rust-clippy/pull/8487)
 +* [`extra_unused_lifetimes`]: Now checks for impl lifetimes
 +  [#8737](https://github.com/rust-lang/rust-clippy/pull/8737)
 +* [`cast_possible_truncation`]: Now catches more cases with larger shift or divide operations
 +  [#8687](https://github.com/rust-lang/rust-clippy/pull/8687)
 +* [`identity_op`]: Now checks for modulo expressions
 +  [#8519](https://github.com/rust-lang/rust-clippy/pull/8519)
 +* [`panic`]: No longer lint in constant context
 +  [#8592](https://github.com/rust-lang/rust-clippy/pull/8592)
 +* [`manual_split_once`]: Now lints manual iteration of `splitn`
 +  [#8717](https://github.com/rust-lang/rust-clippy/pull/8717)
 +* [`self_named_module_files`], [`mod_module_files`]: Now handle relative module paths
 +  [#8611](https://github.com/rust-lang/rust-clippy/pull/8611)
 +* [`unsound_collection_transmute`]: Now has better size and alignment checks
 +  [#8648](https://github.com/rust-lang/rust-clippy/pull/8648)
 +* [`unnested_or_patterns`]: Ignore cases, where the suggestion would be longer
 +  [#8619](https://github.com/rust-lang/rust-clippy/pull/8619)
 +
 +### False Positive Fixes
 +
 +* [`rest_pat_in_fully_bound_structs`]: Now ignores structs marked with `#[non_exhaustive]`
 +  [#8690](https://github.com/rust-lang/rust-clippy/pull/8690)
 +* [`needless_late_init`]: No longer lints `if let` statements, `let mut` bindings or instances that
 +  changes the drop order significantly
 +  [#8617](https://github.com/rust-lang/rust-clippy/pull/8617)
 +* [`unnecessary_cast`]: No longer lints to casts to aliased or non-primitive types
 +  [#8596](https://github.com/rust-lang/rust-clippy/pull/8596)
 +* [`init_numbered_fields`]: No longer lints type aliases
 +  [#8780](https://github.com/rust-lang/rust-clippy/pull/8780)
 +* [`needless_option_as_deref`]: No longer lints for `as_deref_mut` on `Option` values that can't be moved
 +  [#8646](https://github.com/rust-lang/rust-clippy/pull/8646)
 +* [`mistyped_literal_suffixes`]: Now ignores float literals without an exponent
 +  [#8742](https://github.com/rust-lang/rust-clippy/pull/8742)
 +* [`undocumented_unsafe_blocks`]: Now ignores unsafe blocks from proc-macros and works better for sub-expressions
 +  [#8450](https://github.com/rust-lang/rust-clippy/pull/8450)
 +* [`same_functions_in_if_condition`]: Now allows different constants, even if they have the same value
 +  [#8673](https://github.com/rust-lang/rust-clippy/pull/8673)
 +* [`needless_match`]: Now checks for more complex types and ignores type coercion
 +  [#8549](https://github.com/rust-lang/rust-clippy/pull/8549)
 +* [`assertions_on_constants`]: Now ignores constants from `cfg!` macros
 +  [#8614](https://github.com/rust-lang/rust-clippy/pull/8614)
 +* [`indexing_slicing`]: Fix false positives with constant indices in
 +  [#8588](https://github.com/rust-lang/rust-clippy/pull/8588)
 +* [`iter_with_drain`]: Now ignores iterator references
 +  [#8668](https://github.com/rust-lang/rust-clippy/pull/8668)
 +* [`useless_attribute`]: Now allows [`redundant_pub_crate`] on `use` items
 +  [#8743](https://github.com/rust-lang/rust-clippy/pull/8743)
 +* [`cast_ptr_alignment`]: Now ignores expressions, when used for unaligned reads and writes
 +  [#8632](https://github.com/rust-lang/rust-clippy/pull/8632)
 +* [`wrong_self_convention`]: Now allows `&mut self` and no self as arguments for `is_*` methods
 +  [#8738](https://github.com/rust-lang/rust-clippy/pull/8738)
 +* [`mut_from_ref`]: Only lint in unsafe code
 +  [#8647](https://github.com/rust-lang/rust-clippy/pull/8647)
 +* [`redundant_pub_crate`]: Now allows macro exports
 +  [#8736](https://github.com/rust-lang/rust-clippy/pull/8736)
 +* [`needless_match`]: Ignores cases where the else block expression is different
 +  [#8700](https://github.com/rust-lang/rust-clippy/pull/8700)
 +* [`transmute_int_to_char`]: Now allows transmutations in `const` code
 +  [#8610](https://github.com/rust-lang/rust-clippy/pull/8610)
 +* [`manual_non_exhaustive`]: Ignores cases, where the enum value is used
 +  [#8645](https://github.com/rust-lang/rust-clippy/pull/8645)
 +* [`redundant_closure`]: Now ignores coerced closure
 +  [#8431](https://github.com/rust-lang/rust-clippy/pull/8431)
 +* [`identity_op`]: Is now ignored in cases where extra brackets would be needed
 +  [#8730](https://github.com/rust-lang/rust-clippy/pull/8730)
 +* [`let_unit_value`]: Now ignores cases which are used for type inference
 +  [#8563](https://github.com/rust-lang/rust-clippy/pull/8563)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`manual_split_once`]: Fixed incorrect suggestions for single result accesses
 +  [#8631](https://github.com/rust-lang/rust-clippy/pull/8631)
 +* [`bytes_nth`]: Fix typos in the diagnostic message
 +  [#8403](https://github.com/rust-lang/rust-clippy/pull/8403)
 +* [`mistyped_literal_suffixes`]: Now suggests the correct integer types
 +  [#8742](https://github.com/rust-lang/rust-clippy/pull/8742)
 +* [`unnecessary_to_owned`]: Fixed suggestion based on the configured msrv
 +  [#8692](https://github.com/rust-lang/rust-clippy/pull/8692)
 +* [`single_element_loop`]: Improve lint for Edition 2021 arrays
 +  [#8616](https://github.com/rust-lang/rust-clippy/pull/8616)
 +* [`manual_bits`]: Now includes a cast for proper type conversion, when needed
 +  [#8677](https://github.com/rust-lang/rust-clippy/pull/8677)
 +* [`option_map_unit_fn`], [`result_map_unit_fn`]: Fix some incorrect suggestions
 +  [#8584](https://github.com/rust-lang/rust-clippy/pull/8584)
 +* [`collapsible_else_if`]: Add whitespace in suggestion
 +  [#8729](https://github.com/rust-lang/rust-clippy/pull/8729)
 +* [`transmute_bytes_to_str`]: Now suggest `from_utf8_unchecked` in `const` context
 +  [#8612](https://github.com/rust-lang/rust-clippy/pull/8612)
 +* [`map_clone`]: Improve message and suggestion based on the msrv
 +  [#8688](https://github.com/rust-lang/rust-clippy/pull/8688)
 +* [`needless_late_init`]: Now shows the `let` statement where it was first initialized
 +  [#8779](https://github.com/rust-lang/rust-clippy/pull/8779)
 +
 +### ICE Fixes
 +
 +* [`only_used_in_recursion`]
 +  [#8691](https://github.com/rust-lang/rust-clippy/pull/8691)
 +* [`cast_slice_different_sizes`]
 +  [#8720](https://github.com/rust-lang/rust-clippy/pull/8720)
 +* [`iter_overeager_cloned`]
 +  [#8602](https://github.com/rust-lang/rust-clippy/pull/8602)
 +* [`undocumented_unsafe_blocks`]
 +  [#8686](https://github.com/rust-lang/rust-clippy/pull/8686)
 +
 +## Rust 1.61
 +
 +Released 2022-05-19
 +
 +[57b3c4b...d0cf3481](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...d0cf3481)
 +
 +### New Lints
 +
 +* [`only_used_in_recursion`]
 +  [#8422](https://github.com/rust-lang/rust-clippy/pull/8422)
 +* [`cast_enum_truncation`]
 +  [#8381](https://github.com/rust-lang/rust-clippy/pull/8381)
 +* [`missing_spin_loop`]
 +  [#8174](https://github.com/rust-lang/rust-clippy/pull/8174)
 +* [`deref_by_slicing`]
 +  [#8218](https://github.com/rust-lang/rust-clippy/pull/8218)
 +* [`needless_match`]
 +  [#8471](https://github.com/rust-lang/rust-clippy/pull/8471)
 +* [`allow_attributes_without_reason`] (Requires `#![feature(lint_reasons)]`)
 +  [#8504](https://github.com/rust-lang/rust-clippy/pull/8504)
 +* [`print_in_format_impl`]
 +  [#8253](https://github.com/rust-lang/rust-clippy/pull/8253)
 +* [`unnecessary_find_map`]
 +  [#8489](https://github.com/rust-lang/rust-clippy/pull/8489)
 +* [`or_then_unwrap`]
 +  [#8561](https://github.com/rust-lang/rust-clippy/pull/8561)
 +* [`unnecessary_join`]
 +  [#8579](https://github.com/rust-lang/rust-clippy/pull/8579)
 +* [`iter_with_drain`]
 +  [#8483](https://github.com/rust-lang/rust-clippy/pull/8483)
 +* [`cast_enum_constructor`]
 +  [#8562](https://github.com/rust-lang/rust-clippy/pull/8562)
 +* [`cast_slice_different_sizes`]
 +  [#8445](https://github.com/rust-lang/rust-clippy/pull/8445)
 +
 +### Moves and Deprecations
 +
 +* Moved [`transmute_undefined_repr`] to `nursery` (now allow-by-default)
 +  [#8432](https://github.com/rust-lang/rust-clippy/pull/8432)
 +* Moved [`try_err`] to `restriction`
 +  [#8544](https://github.com/rust-lang/rust-clippy/pull/8544)
 +* Move [`iter_with_drain`] to `nursery`
 +  [#8541](https://github.com/rust-lang/rust-clippy/pull/8541)
 +* Renamed `to_string_in_display` to [`recursive_format_impl`]
 +  [#8188](https://github.com/rust-lang/rust-clippy/pull/8188)
 +
 +### Enhancements
 +
 +* [`dbg_macro`]: The lint level can now be set with crate attributes and works inside macros
 +  [#8411](https://github.com/rust-lang/rust-clippy/pull/8411)
 +* [`ptr_as_ptr`]: Now works inside macros
 +  [#8442](https://github.com/rust-lang/rust-clippy/pull/8442)
 +* [`use_self`]: Now works for variants in match expressions
 +  [#8456](https://github.com/rust-lang/rust-clippy/pull/8456)
 +* [`await_holding_lock`]: Now lints for `parking_lot::{Mutex, RwLock}`
 +  [#8419](https://github.com/rust-lang/rust-clippy/pull/8419)
 +* [`recursive_format_impl`]: Now checks for format calls on `self`
 +  [#8188](https://github.com/rust-lang/rust-clippy/pull/8188)
 +
 +### False Positive Fixes
 +
 +* [`new_without_default`]: No longer lints for `new()` methods with `#[doc(hidden)]`
 +  [#8472](https://github.com/rust-lang/rust-clippy/pull/8472)
 +* [`transmute_undefined_repr`]: No longer lints for single field structs with `#[repr(C)]`,
 +  generic parameters, wide pointers, unions, tuples and allow several forms of type erasure
 +  [#8425](https://github.com/rust-lang/rust-clippy/pull/8425)
 +  [#8553](https://github.com/rust-lang/rust-clippy/pull/8553)
 +  [#8440](https://github.com/rust-lang/rust-clippy/pull/8440)
 +  [#8547](https://github.com/rust-lang/rust-clippy/pull/8547)
 +* [`match_single_binding`], [`match_same_arms`], [`match_as_ref`], [`match_bool`]: No longer
 +  lint `match` expressions with `cfg`ed arms
 +  [#8443](https://github.com/rust-lang/rust-clippy/pull/8443)
 +* [`single_component_path_imports`]: No longer lint on macros
 +  [#8537](https://github.com/rust-lang/rust-clippy/pull/8537)
 +* [`ptr_arg`]: Allow `&mut` arguments for `Cow<_>`
 +  [#8552](https://github.com/rust-lang/rust-clippy/pull/8552)
 +* [`needless_borrow`]: No longer lints for method calls
 +  [#8441](https://github.com/rust-lang/rust-clippy/pull/8441)
 +* [`match_same_arms`]: Now ensures that interposing arm patterns don't overlap
 +  [#8232](https://github.com/rust-lang/rust-clippy/pull/8232)
 +* [`default_trait_access`]: Now allows `Default::default` in update expressions
 +  [#8433](https://github.com/rust-lang/rust-clippy/pull/8433)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`redundant_slicing`]: Fixed suggestion for a method calls
 +  [#8218](https://github.com/rust-lang/rust-clippy/pull/8218)
 +* [`map_flatten`]: Long suggestions will now be split up into two help messages
 +  [#8520](https://github.com/rust-lang/rust-clippy/pull/8520)
 +* [`unnecessary_lazy_evaluations`]: Now shows suggestions for longer code snippets
 +  [#8543](https://github.com/rust-lang/rust-clippy/pull/8543)
 +* [`unnecessary_sort_by`]: Now suggests `Reverse` including the path
 +  [#8462](https://github.com/rust-lang/rust-clippy/pull/8462)
 +* [`search_is_some`]: More suggestions are now `MachineApplicable`
 +  [#8536](https://github.com/rust-lang/rust-clippy/pull/8536)
 +
 +### Documentation Improvements
 +
 +* [`new_without_default`]: Document `pub` requirement for the struct and fields
 +  [#8429](https://github.com/rust-lang/rust-clippy/pull/8429)
 +
 +## Rust 1.60
 +
 +Released 2022-04-07
 +
 +[0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b)
 +
 +### New Lints
 +
 +* [`single_char_lifetime_names`]
 +  [#8236](https://github.com/rust-lang/rust-clippy/pull/8236)
 +* [`iter_overeager_cloned`]
 +  [#8203](https://github.com/rust-lang/rust-clippy/pull/8203)
 +* [`transmute_undefined_repr`]
 +  [#8398](https://github.com/rust-lang/rust-clippy/pull/8398)
 +* [`default_union_representation`]
 +  [#8289](https://github.com/rust-lang/rust-clippy/pull/8289)
 +* [`manual_bits`]
 +  [#8213](https://github.com/rust-lang/rust-clippy/pull/8213)
 +* [`borrow_as_ptr`]
 +  [#8210](https://github.com/rust-lang/rust-clippy/pull/8210)
 +
 +### Moves and Deprecations
 +
 +* Moved [`disallowed_methods`] and [`disallowed_types`] to `style` (now warn-by-default)
 +  [#8261](https://github.com/rust-lang/rust-clippy/pull/8261)
 +* Rename `ref_in_deref` to [`needless_borrow`]
 +  [#8217](https://github.com/rust-lang/rust-clippy/pull/8217)
 +* Moved [`mutex_atomic`] to `nursery` (now allow-by-default)
 +  [#8260](https://github.com/rust-lang/rust-clippy/pull/8260)
 +
 +### Enhancements
 +
 +* [`ptr_arg`]: Now takes the argument usage into account and lints for mutable references
 +  [#8271](https://github.com/rust-lang/rust-clippy/pull/8271)
 +* [`unused_io_amount`]: Now supports async read and write traits
 +  [#8179](https://github.com/rust-lang/rust-clippy/pull/8179)
 +* [`while_let_on_iterator`]: Improved detection to catch more cases
 +  [#8221](https://github.com/rust-lang/rust-clippy/pull/8221)
 +* [`trait_duplication_in_bounds`]: Now covers trait functions with `Self` bounds
 +  [#8252](https://github.com/rust-lang/rust-clippy/pull/8252)
 +* [`unwrap_used`]: Now works for `.get(i).unwrap()` and `.get_mut(i).unwrap()`
 +  [#8372](https://github.com/rust-lang/rust-clippy/pull/8372)
 +* [`map_clone`]: The suggestion takes `msrv` into account
 +  [#8280](https://github.com/rust-lang/rust-clippy/pull/8280)
 +* [`manual_bits`] and [`borrow_as_ptr`]: Now track the `clippy::msrv` attribute
 +  [#8280](https://github.com/rust-lang/rust-clippy/pull/8280)
 +* [`disallowed_methods`]: Now works for methods on primitive types
 +  [#8112](https://github.com/rust-lang/rust-clippy/pull/8112)
 +* [`not_unsafe_ptr_arg_deref`]: Now works for type aliases
 +  [#8273](https://github.com/rust-lang/rust-clippy/pull/8273)
 +* [`needless_question_mark`]: Now works for async functions
 +  [#8311](https://github.com/rust-lang/rust-clippy/pull/8311)
 +* [`iter_not_returning_iterator`]: Now handles type projections
 +  [#8228](https://github.com/rust-lang/rust-clippy/pull/8228)
 +* [`wrong_self_convention`]: Now detects wrong `self` references in more cases
 +  [#8208](https://github.com/rust-lang/rust-clippy/pull/8208)
 +* [`single_match`]: Now works for `match` statements with tuples
 +  [#8322](https://github.com/rust-lang/rust-clippy/pull/8322)
 +
 +### False Positive Fixes
 +
 +* [`erasing_op`]: No longer triggers if the output type changes
 +  [#8204](https://github.com/rust-lang/rust-clippy/pull/8204)
 +* [`if_same_then_else`]: No longer triggers for `if let` statements
 +  [#8297](https://github.com/rust-lang/rust-clippy/pull/8297)
 +* [`manual_memcpy`]: No longer lints on `VecDeque`
 +  [#8226](https://github.com/rust-lang/rust-clippy/pull/8226)
 +* [`trait_duplication_in_bounds`]: Now takes path segments into account
 +  [#8315](https://github.com/rust-lang/rust-clippy/pull/8315)
 +* [`deref_addrof`]: No longer lints when the dereference or borrow occurs in different a context
 +  [#8268](https://github.com/rust-lang/rust-clippy/pull/8268)
 +* [`type_repetition_in_bounds`]: Now checks for full equality to prevent false positives
 +  [#8224](https://github.com/rust-lang/rust-clippy/pull/8224)
 +* [`ptr_arg`]: No longer lint for mutable references in traits
 +  [#8369](https://github.com/rust-lang/rust-clippy/pull/8369)
 +* [`implicit_clone`]: No longer lints for double references
 +  [#8231](https://github.com/rust-lang/rust-clippy/pull/8231)
 +* [`needless_lifetimes`]: No longer lints lifetimes for explicit `self` types
 +  [#8278](https://github.com/rust-lang/rust-clippy/pull/8278)
 +* [`op_ref`]: No longer lints in `BinOp` impl if that can cause recursion
 +  [#8298](https://github.com/rust-lang/rust-clippy/pull/8298)
 +* [`enum_variant_names`]: No longer triggers for empty variant names
 +  [#8329](https://github.com/rust-lang/rust-clippy/pull/8329)
 +* [`redundant_closure`]: No longer lints for `Arc<T>` or `Rc<T>`
 +  [#8193](https://github.com/rust-lang/rust-clippy/pull/8193)
 +* [`iter_not_returning_iterator`]: No longer lints on trait implementations but therefore on trait definitions
 +  [#8228](https://github.com/rust-lang/rust-clippy/pull/8228)
 +* [`single_match`]: No longer lints on exhaustive enum patterns without a wildcard
 +  [#8322](https://github.com/rust-lang/rust-clippy/pull/8322)
 +* [`manual_swap`]: No longer lints on cases that involve automatic dereferences
 +  [#8220](https://github.com/rust-lang/rust-clippy/pull/8220)
 +* [`useless_format`]: Now works for implicit named arguments
 +  [#8295](https://github.com/rust-lang/rust-clippy/pull/8295)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`needless_borrow`]: Prevent mutable borrows being moved and suggest removing the borrow on method calls
 +  [#8217](https://github.com/rust-lang/rust-clippy/pull/8217)
 +* [`chars_next_cmp`]: Correctly escapes the suggestion
 +  [#8376](https://github.com/rust-lang/rust-clippy/pull/8376)
 +* [`explicit_write`]: Add suggestions for `write!`s with format arguments
 +  [#8365](https://github.com/rust-lang/rust-clippy/pull/8365)
 +* [`manual_memcpy`]: Suggests `copy_from_slice` when applicable
 +  [#8226](https://github.com/rust-lang/rust-clippy/pull/8226)
 +* [`or_fun_call`]: Improved suggestion display for long arguments
 +  [#8292](https://github.com/rust-lang/rust-clippy/pull/8292)
 +* [`unnecessary_cast`]: Now correctly includes the sign
 +  [#8350](https://github.com/rust-lang/rust-clippy/pull/8350)
 +* [`cmp_owned`]: No longer flips the comparison order
 +  [#8299](https://github.com/rust-lang/rust-clippy/pull/8299)
 +* [`explicit_counter_loop`]: Now correctly suggests `iter()` on references
 +  [#8382](https://github.com/rust-lang/rust-clippy/pull/8382)
 +
 +### ICE Fixes
 +
 +* [`manual_split_once`]
 +  [#8250](https://github.com/rust-lang/rust-clippy/pull/8250)
 +
 +### Documentation Improvements
 +
 +* [`map_flatten`]: Add documentation for the `Option` type
 +  [#8354](https://github.com/rust-lang/rust-clippy/pull/8354)
 +* Document that Clippy's driver might use a different code generation than rustc
 +  [#8037](https://github.com/rust-lang/rust-clippy/pull/8037)
 +* Clippy's lint list will now automatically focus the search box
 +  [#8343](https://github.com/rust-lang/rust-clippy/pull/8343)
 +
 +### Others
 +
 +* Clippy now warns if we find multiple Clippy config files exist
 +  [#8326](https://github.com/rust-lang/rust-clippy/pull/8326)
 +
 +## Rust 1.59
 +
 +Released 2022-02-24
 +
 +[e181011...0eff589](https://github.com/rust-lang/rust-clippy/compare/e181011...0eff589)
 +
 +### New Lints
 +
 +* [`index_refutable_slice`]
 +  [#7643](https://github.com/rust-lang/rust-clippy/pull/7643)
 +* [`needless_splitn`]
 +  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
 +* [`unnecessary_to_owned`]
 +  [#7978](https://github.com/rust-lang/rust-clippy/pull/7978)
 +* [`needless_late_init`]
 +  [#7995](https://github.com/rust-lang/rust-clippy/pull/7995)
 +* [`octal_escapes`] [#8007](https://github.com/rust-lang/rust-clippy/pull/8007)
 +* [`return_self_not_must_use`]
 +  [#8071](https://github.com/rust-lang/rust-clippy/pull/8071)
 +* [`init_numbered_fields`]
 +  [#8170](https://github.com/rust-lang/rust-clippy/pull/8170)
 +
 +### Moves and Deprecations
 +
 +* Move `if_then_panic` to `pedantic` and rename to [`manual_assert`] (now
 +  allow-by-default) [#7810](https://github.com/rust-lang/rust-clippy/pull/7810)
 +* Rename `disallow_type` to [`disallowed_types`] and `disallowed_method` to
 +  [`disallowed_methods`]
 +  [#7984](https://github.com/rust-lang/rust-clippy/pull/7984)
 +* Move [`map_flatten`] to `complexity` (now warn-by-default)
 +  [#8054](https://github.com/rust-lang/rust-clippy/pull/8054)
 +
 +### Enhancements
 +
 +* [`match_overlapping_arm`]: Fix false negative where after included ranges,
 +  overlapping ranges weren't linted anymore
 +  [#7909](https://github.com/rust-lang/rust-clippy/pull/7909)
 +* [`deprecated_cfg_attr`]: Now takes the specified MSRV into account
 +  [#7944](https://github.com/rust-lang/rust-clippy/pull/7944)
 +* [`cast_lossless`]: Now also lints for `bool` to integer casts
 +  [#7948](https://github.com/rust-lang/rust-clippy/pull/7948)
 +* [`let_underscore_lock`]: Also emit lints for the `parking_lot` crate
 +  [#7957](https://github.com/rust-lang/rust-clippy/pull/7957)
 +* [`needless_borrow`]
 +  [#7977](https://github.com/rust-lang/rust-clippy/pull/7977)
 +    * Lint when a borrow is auto-dereffed more than once
 +    * Lint in the trailing expression of a block for a match arm
 +* [`strlen_on_c_strings`]
 +  [8001](https://github.com/rust-lang/rust-clippy/pull/8001)
 +    * Lint when used without a fully-qualified path
 +    * Suggest removing the surrounding unsafe block when possible
 +* [`non_ascii_literal`]: Now also lints on `char`s, not just `string`s
 +  [#8034](https://github.com/rust-lang/rust-clippy/pull/8034)
 +* [`single_char_pattern`]: Now also lints on `split_inclusive`, `split_once`,
 +  `rsplit_once`, `replace`, and `replacen`
 +  [#8077](https://github.com/rust-lang/rust-clippy/pull/8077)
 +* [`unwrap_or_else_default`]: Now also lints on `std` constructors like
 +  `Vec::new`, `HashSet::new`, and `HashMap::new`
 +  [#8163](https://github.com/rust-lang/rust-clippy/pull/8163)
 +* [`shadow_reuse`]: Now also lints on shadowed `if let` bindings, instead of
 +  [`shadow_unrelated`]
 +  [#8165](https://github.com/rust-lang/rust-clippy/pull/8165)
 +
 +### False Positive Fixes
 +
 +* [`or_fun_call`], [`unnecessary_lazy_evaluations`]: Improve heuristics, so that
 +  cheap functions (e.g. calling `.len()` on a `Vec`) won't get linted anymore
 +  [#7639](https://github.com/rust-lang/rust-clippy/pull/7639)
 +* [`manual_split_once`]: No longer suggests code changing the original behavior
 +  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
 +* Don't show [`no_effect`] or [`unnecessary_operation`] warning for unit struct
 +  implementing `FnOnce`
 +  [#7898](https://github.com/rust-lang/rust-clippy/pull/7898)
 +* [`semicolon_if_nothing_returned`]: Fixed a bug, where the lint wrongly
 +  triggered on `let-else` statements
 +  [#7955](https://github.com/rust-lang/rust-clippy/pull/7955)
 +* [`if_then_some_else_none`]: No longer lints if there is an early return
 +  [#7980](https://github.com/rust-lang/rust-clippy/pull/7980)
 +* [`needless_collect`]: No longer suggests removal of `collect` when removal
 +  would create code requiring mutably borrowing a value multiple times
 +  [#7982](https://github.com/rust-lang/rust-clippy/pull/7982)
 +* [`shadow_same`]: Fix false positive for `async` function's params
 +  [#7997](https://github.com/rust-lang/rust-clippy/pull/7997)
 +* [`suboptimal_flops`]: No longer triggers in constant functions
 +  [#8009](https://github.com/rust-lang/rust-clippy/pull/8009)
 +* [`type_complexity`]: No longer lints on associated types in traits
 +  [#8030](https://github.com/rust-lang/rust-clippy/pull/8030)
 +* [`question_mark`]: No longer lints if returned object is not local
 +  [#8080](https://github.com/rust-lang/rust-clippy/pull/8080)
 +* [`option_if_let_else`]: No longer lint on complex sub-patterns
 +  [#8086](https://github.com/rust-lang/rust-clippy/pull/8086)
 +* [`blocks_in_if_conditions`]: No longer lints on empty closures
 +  [#8100](https://github.com/rust-lang/rust-clippy/pull/8100)
 +* [`enum_variant_names`]: No longer lint when first prefix is only a substring
 +  of a camel-case word
 +  [#8127](https://github.com/rust-lang/rust-clippy/pull/8127)
 +* [`identity_op`]: Only lint on integral operands
 +  [#8183](https://github.com/rust-lang/rust-clippy/pull/8183)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`search_is_some`]: Fix suggestion for `any()` not taking item by reference
 +  [#7463](https://github.com/rust-lang/rust-clippy/pull/7463)
 +* [`almost_swapped`]: Now detects if there is a `no_std` or `no_core` attribute
 +  and adapts the suggestion accordingly
 +  [#7877](https://github.com/rust-lang/rust-clippy/pull/7877)
 +* [`redundant_pattern_matching`]: Fix suggestion for deref expressions
 +  [#7949](https://github.com/rust-lang/rust-clippy/pull/7949)
 +* [`explicit_counter_loop`]: Now also produces a suggestion for non-`usize`
 +  types [#7950](https://github.com/rust-lang/rust-clippy/pull/7950)
 +* [`manual_map`]: Fix suggestion when used with unsafe functions and blocks
 +  [#7968](https://github.com/rust-lang/rust-clippy/pull/7968)
 +* [`option_map_or_none`]: Suggest `map` over `and_then` when possible
 +  [#7971](https://github.com/rust-lang/rust-clippy/pull/7971)
 +* [`option_if_let_else`]: No longer expands macros in the suggestion
 +  [#7974](https://github.com/rust-lang/rust-clippy/pull/7974)
 +* [`iter_cloned_collect`]: Suggest `copied` over `cloned` when possible
 +  [#8006](https://github.com/rust-lang/rust-clippy/pull/8006)
 +* [`doc_markdown`]: No longer uses inline hints to improve readability of
 +  suggestion [#8011](https://github.com/rust-lang/rust-clippy/pull/8011)
 +* [`needless_question_mark`]: Now better explains the suggestion
 +  [#8028](https://github.com/rust-lang/rust-clippy/pull/8028)
 +* [`single_char_pattern`]: Escape backslash `\` in suggestion
 +  [#8067](https://github.com/rust-lang/rust-clippy/pull/8067)
 +* [`needless_bool`]: Suggest `a != b` over `!(a == b)`
 +  [#8117](https://github.com/rust-lang/rust-clippy/pull/8117)
 +* [`iter_skip_next`]: Suggest to add a `mut` if it is necessary in order to
 +  apply this lints suggestion
 +  [#8133](https://github.com/rust-lang/rust-clippy/pull/8133)
 +* [`neg_multiply`]: Now produces a suggestion
 +  [#8144](https://github.com/rust-lang/rust-clippy/pull/8144)
 +* [`needless_return`]: Now suggests the unit type `()` over an empty block `{}`
 +  in match arms [#8185](https://github.com/rust-lang/rust-clippy/pull/8185)
 +* [`suboptimal_flops`]: Now gives a syntactically correct suggestion for
 +  `to_radians` and `to_degrees`
 +  [#8187](https://github.com/rust-lang/rust-clippy/pull/8187)
 +
 +### ICE Fixes
 +
 +* [`undocumented_unsafe_blocks`]
 +  [#7945](https://github.com/rust-lang/rust-clippy/pull/7945)
 +  [#7988](https://github.com/rust-lang/rust-clippy/pull/7988)
 +* [`unnecessary_cast`]
 +  [#8167](https://github.com/rust-lang/rust-clippy/pull/8167)
 +
 +### Documentation Improvements
 +
 +* [`print_stdout`], [`print_stderr`], [`dbg_macro`]: Document how the lint level
 +  can be changed crate-wide
 +  [#8040](https://github.com/rust-lang/rust-clippy/pull/8040)
 +* Added a note to the `README` that config changes don't apply to already
 +  compiled code [#8175](https://github.com/rust-lang/rust-clippy/pull/8175)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now displays
 +  the version a lint was added. :tada:
 +  [#7813](https://github.com/rust-lang/rust-clippy/pull/7813)
 +* New and improved issue templates
 +  [#8032](https://github.com/rust-lang/rust-clippy/pull/8032)
 +* _Dev:_ Add `cargo dev lint` command, to run your modified Clippy version on a
 +  file [#7917](https://github.com/rust-lang/rust-clippy/pull/7917)
 +
 +## Rust 1.58
 +
 +Released 2022-01-13
 +
 +[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011)
 +
 +### Rust 1.58.1
 +
 +* Move [`non_send_fields_in_send_ty`] to `nursery` (now allow-by-default)
 +  [#8075](https://github.com/rust-lang/rust-clippy/pull/8075)
 +* [`useless_format`]: Handle implicit named arguments
 +  [#8295](https://github.com/rust-lang/rust-clippy/pull/8295)
 +
 +### New lints
 +
 +* [`transmute_num_to_bytes`]
 +  [#7805](https://github.com/rust-lang/rust-clippy/pull/7805)
 +* [`match_str_case_mismatch`]
 +  [#7806](https://github.com/rust-lang/rust-clippy/pull/7806)
 +* [`format_in_format_args`], [`to_string_in_format_args`]
 +  [#7743](https://github.com/rust-lang/rust-clippy/pull/7743)
 +* [`uninit_vec`]
 +  [#7682](https://github.com/rust-lang/rust-clippy/pull/7682)
 +* [`fn_to_numeric_cast_any`]
 +  [#7705](https://github.com/rust-lang/rust-clippy/pull/7705)
 +* [`undocumented_unsafe_blocks`]
 +  [#7748](https://github.com/rust-lang/rust-clippy/pull/7748)
 +* [`trailing_empty_array`]
 +  [#7838](https://github.com/rust-lang/rust-clippy/pull/7838)
 +* [`string_slice`]
 +  [#7878](https://github.com/rust-lang/rust-clippy/pull/7878)
 +
 +### Moves or deprecations of lints
 +
 +* Move [`non_send_fields_in_send_ty`] to `suspicious`
 +  [#7874](https://github.com/rust-lang/rust-clippy/pull/7874)
 +* Move [`non_ascii_literal`] to `restriction`
 +  [#7907](https://github.com/rust-lang/rust-clippy/pull/7907)
 +
 +### Changes that expand what code existing lints cover
 +
 +* [`question_mark`] now covers `Result`
 +  [#7840](https://github.com/rust-lang/rust-clippy/pull/7840)
 +* Make [`useless_format`] recognize bare `format!("")`
 +  [#7801](https://github.com/rust-lang/rust-clippy/pull/7801)
 +* Lint on underscored variables with no side effects in [`no_effect`]
 +  [#7775](https://github.com/rust-lang/rust-clippy/pull/7775)
 +* Expand [`match_ref_pats`] to check for multiple reference patterns
 +  [#7800](https://github.com/rust-lang/rust-clippy/pull/7800)
 +
 +### False positive fixes
 +
 +* Fix false positive of [`implicit_saturating_sub`] with `else` clause
 +  [#7832](https://github.com/rust-lang/rust-clippy/pull/7832)
 +* Fix [`question_mark`] when there is call in conditional predicate
 +  [#7860](https://github.com/rust-lang/rust-clippy/pull/7860)
 +* [`mut_mut`] no longer lints when type is defined in external macros
 +  [#7795](https://github.com/rust-lang/rust-clippy/pull/7795)
 +* Avoid [`eq_op`] in test functions
 +  [#7811](https://github.com/rust-lang/rust-clippy/pull/7811)
 +* [`cast_possible_truncation`] no longer lints when cast is coming from `signum`
 +  method call [#7850](https://github.com/rust-lang/rust-clippy/pull/7850)
 +* [`match_str_case_mismatch`] no longer lints on uncased characters
 +  [#7865](https://github.com/rust-lang/rust-clippy/pull/7865)
 +* [`ptr_arg`] no longer lints references to type aliases
 +  [#7890](https://github.com/rust-lang/rust-clippy/pull/7890)
 +* [`missing_safety_doc`] now also accepts "implementation safety" headers
 +  [#7856](https://github.com/rust-lang/rust-clippy/pull/7856)
 +* [`missing_safety_doc`] no longer lints if any parent has `#[doc(hidden)]`
 +  attribute [#7849](https://github.com/rust-lang/rust-clippy/pull/7849)
 +* [`if_not_else`] now ignores else-if statements
 +  [#7895](https://github.com/rust-lang/rust-clippy/pull/7895)
 +* Avoid linting [`cast_possible_truncation`] on bit-reducing operations
 +  [#7819](https://github.com/rust-lang/rust-clippy/pull/7819)
 +* Avoid linting [`field_reassign_with_default`] when `Drop` and `Copy` are
 +  involved [#7794](https://github.com/rust-lang/rust-clippy/pull/7794)
 +* [`unnecessary_sort_by`] now checks if argument implements `Ord` trait
 +  [#7824](https://github.com/rust-lang/rust-clippy/pull/7824)
 +* Fix false positive in [`match_overlapping_arm`]
 +  [#7847](https://github.com/rust-lang/rust-clippy/pull/7847)
 +* Prevent [`needless_lifetimes`] false positive in `async` function definition
 +  [#7901](https://github.com/rust-lang/rust-clippy/pull/7901)
 +
 +### Suggestion fixes/improvements
 +
 +* Keep an initial `::` when [`doc_markdown`] suggests to use ticks
 +  [#7916](https://github.com/rust-lang/rust-clippy/pull/7916)
 +* Add a machine applicable suggestion for the [`doc_markdown`] missing backticks
 +  lint [#7904](https://github.com/rust-lang/rust-clippy/pull/7904)
 +* [`equatable_if_let`] no longer expands macros in the suggestion
 +  [#7788](https://github.com/rust-lang/rust-clippy/pull/7788)
 +* Make [`shadow_reuse`] suggestion less verbose
 +  [#7782](https://github.com/rust-lang/rust-clippy/pull/7782)
 +
 +### ICE fixes
 +
 +* Fix ICE in [`enum_variant_names`]
 +  [#7873](https://github.com/rust-lang/rust-clippy/pull/7873)
 +* Fix ICE in [`undocumented_unsafe_blocks`]
 +  [#7891](https://github.com/rust-lang/rust-clippy/pull/7891)
 +
 +### Documentation improvements
 +
 +* Fixed naive doc formatting for `#[must_use]` lints ([`must_use_unit`],
 +  [`double_must_use`], [`must_use_candidate`], [`let_underscore_must_use`])
 +  [#7827](https://github.com/rust-lang/rust-clippy/pull/7827)
 +* Fix typo in example for [`match_result_ok`]
 +  [#7815](https://github.com/rust-lang/rust-clippy/pull/7815)
 +
 +### Others
 +
 +* Allow giving reasons for [`disallowed_types`]
 +  [#7791](https://github.com/rust-lang/rust-clippy/pull/7791)
 +* Fix [`manual_assert`] and [`match_wild_err_arm`] for `#![no_std]` and Rust
 +  2021. [#7851](https://github.com/rust-lang/rust-clippy/pull/7851)
 +* Fix regression in [`semicolon_if_nothing_returned`] on macros containing while
 +  loops [#7789](https://github.com/rust-lang/rust-clippy/pull/7789)
 +* Added a new configuration `literal-suffix-style` to enforce a certain style
 +  writing [`unseparated_literal_suffix`]
 +  [#7726](https://github.com/rust-lang/rust-clippy/pull/7726)
 +
 +## Rust 1.57
 +
 +Released 2021-12-02
 +
 +[7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa)
 +
 +### New Lints
 +
 +* [`negative_feature_names`]
 +  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
 +* [`redundant_feature_names`]
 +  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
 +* [`mod_module_files`]
 +  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
 +* [`self_named_module_files`]
 +  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
 +* [`manual_split_once`]
 +  [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
 +* [`derivable_impls`]
 +  [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
 +* [`needless_option_as_deref`]
 +  [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
 +* [`iter_not_returning_iterator`]
 +  [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
 +* [`same_name_method`]
 +  [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
 +* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
 +* [`non_send_fields_in_send_ty`]
 +  [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
 +* [`equatable_if_let`]
 +  [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
 +
 +### Moves and Deprecations
 +
 +* Move [`shadow_unrelated`] to `restriction`
 +  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
 +* Move [`option_if_let_else`] to `nursery`
 +  [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
 +* Move [`branches_sharing_code`] to `nursery`
 +  [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
 +* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
 +  `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
 +* Move [`many_single_char_names`] to `pedantic`
 +  [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
 +* Move [`float_cmp`] to `pedantic`
 +  [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
 +* Rename `box_vec` to [`box_collection`] and lint on more general cases
 +  [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
 +* Uplift `invalid_atomic_ordering` to rustc
 +  [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
 +
 +### Enhancements
 +
 +* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
 +  limited to certain patterns
 +  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
 +* The `avoid-breaking-exported-api` configuration now also works for
 +  [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
 +  [`option_option`], [`linkedlist`], [`rc_mutex`]
 +  [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
 +* [`unnecessary_unwrap`]: Now also checks for `expect`s
 +  [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
 +* [`disallowed_methods`]: Allow adding a reason that will be displayed with the
 +  lint message
 +  [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
 +* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
 +  [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
 +* [`approx_constant`]: Add `TAU`
 +  [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
 +* [`needless_borrow`]: Now also lints on needless mutable borrows
 +  [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
 +* [`missing_safety_doc`]: Now also lints on unsafe traits
 +  [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
 +
 +### False Positive Fixes
 +
 +* [`manual_map`]: No longer lints when the option is borrowed in the match and
 +  also consumed in the arm
 +  [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
 +* [`filter_next`]: No longer lints if `filter` method is not the
 +  `Iterator::filter` method
 +  [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
 +* [`manual_flatten`]: No longer lints if expression is used after `if let`
 +  [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
 +* [`option_if_let_else`]: Multiple fixes
 +  [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
 +    * `break` and `continue` statements local to the would-be closure are
 +      allowed
 +    * Don't lint in const contexts
 +    * Don't lint when yield expressions are used
 +    * Don't lint when the captures made by the would-be closure conflict with
 +      the other branch
 +    * Don't lint when a field of a local is used when the type could be
 +      potentially moved from
 +    * In some cases, don't lint when scrutinee expression conflicts with the
 +      captures of the would-be closure
 +* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
 +  wide pointers with thin pointers
 +  [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
 +* [`bool_assert_comparison`]: No longer lints on types that do not implement the
 +  `Not` trait with `Output = bool`
 +  [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
 +* [`mut_range_bound`]: No longer lints on range bound mutations, that are
 +  immediately followed by a `break;`
 +  [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
 +* [`mutable_key_type`]: Improve accuracy and document remaining false positives
 +  and false negatives
 +  [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
 +* [`redundant_closure`]: Rewrite the lint to fix various false positives and
 +  false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
 +* [`large_enum_variant`]: No longer wrongly identifies the second largest
 +  variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
 +* [`needless_return`]: No longer lints on let-else expressions
 +  [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
 +* [`suspicious_else_formatting`]: No longer lints in proc-macros
 +  [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
 +* [`excessive_precision`]: No longer lints when in some cases the float was
 +  already written in the shortest form
 +  [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
 +* [`doc_markdown`]: No longer lints on intra-doc links
 +  [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
 +  function call in an indexing operation
 +  [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
 +* [`manual_split_once`]: Produce semantically equivalent suggestion when
 +  `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
 +* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
 +  [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
 +* [`manual_assert`]: No better handles complex conditions
 +  [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
 +* Correctly handle signs in exponents in numeric literals lints
 +  [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
 +* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
 +  [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
 +* Drop exponent from suggestion if it is 0 in numeric literals lints
 +  [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
 +
 +### ICE Fixes
 +
 +* [`implicit_hasher`]
 +  [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
 +
 +### Others
 +
 +* Clippy now uses the 2021
 +  [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
 +  [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
 +
 +## Rust 1.56
 +
 +Released 2021-10-21
 +
 +[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
 +
 +### New Lints
 +
 +* [`unwrap_or_else_default`]
 +  [#7516](https://github.com/rust-lang/rust-clippy/pull/7516)
 +
 +### Enhancements
 +
 +* [`needless_continue`]: Now also lints in `loop { continue; }` case
 +  [#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
 +* [`disallowed_types`]: Now also primitive types can be disallowed
 +  [#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
 +* [`manual_swap`]: Now also lints on xor swaps
 +  [#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
 +* [`map_flatten`]: Now also lints on the `Result` type
 +  [#7522](https://github.com/rust-lang/rust-clippy/pull/7522)
 +* [`no_effect`]: Now also lints on inclusive ranges
 +  [#7556](https://github.com/rust-lang/rust-clippy/pull/7556)
 +
 +### False Positive Fixes
 +
 +* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros
 +  [#7478](https://github.com/rust-lang/rust-clippy/pull/7478)
 +* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics
 +  [#7534](https://github.com/rust-lang/rust-clippy/pull/7534)
 +* [`similar_names`]: No longer complains about `iter` and `item` being too
 +  similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`similar_names`]: No longer suggests to insert or add an underscore as a fix
 +  [#7221](https://github.com/rust-lang/rust-clippy/pull/7221)
 +* [`new_without_default`]: No longer shows the full qualified type path when
 +  suggesting adding a `Default` implementation
 +  [#7493](https://github.com/rust-lang/rust-clippy/pull/7493)
 +* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references
 +  [#7520](https://github.com/rust-lang/rust-clippy/pull/7520)
 +* [`extend_with_drain`]: Improve code suggestion for mutable and immutable
 +  references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533)
 +* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type
 +  [#7535](https://github.com/rust-lang/rust-clippy/pull/7535)
 +* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when
 +  applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541)
 +
 +### Documentation Improvements
 +
 +* Clippy now uses a lint to generate its lint documentation. [Lints all the way
 +  down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
 +  [#7502](https://github.com/rust-lang/rust-clippy/pull/7502)
 +* Reworked Clippy's website:
 +  [#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
 +  [#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
 +  * Added applicability information about lints
 +  * Added a link to jump into the implementation
 +  * Improved loading times
 +  * Adapted some styling
 +* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag
 +  [#7492](https://github.com/rust-lang/rust-clippy/pull/7492)
 +* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
 +  example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
 +
 +## Rust 1.55
 +
 +Released 2021-09-09
 +
 +[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
 +
 +### Important Changes
 +
 +* Stabilized `cargo clippy --fix` :tada:
 +  [#7405](https://github.com/rust-lang/rust-clippy/pull/7405)
 +
 +### New Lints
 +
 +* [`rc_mutex`]
 +  [#7316](https://github.com/rust-lang/rust-clippy/pull/7316)
 +* [`nonstandard_macro_braces`]
 +  [#7299](https://github.com/rust-lang/rust-clippy/pull/7299)
 +* [`strlen_on_c_strings`]
 +  [#7243](https://github.com/rust-lang/rust-clippy/pull/7243)
 +* [`self_named_constructors`]
 +  [#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
 +* [`disallowed_script_idents`]
 +  [#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
 +* [`disallowed_types`]
 +  [#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
 +* [`missing_enforced_import_renames`]
 +  [#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
 +* [`extend_with_drain`]
 +  [#7270](https://github.com/rust-lang/rust-clippy/pull/7270)
 +
 +### Moves and Deprecations
 +
 +* Moved [`from_iter_instead_of_collect`] to `pedantic`
 +  [#7375](https://github.com/rust-lang/rust-clippy/pull/7375)
 +* Added `suspicious` as a new lint group for *code that is most likely wrong or useless*
 +  [#7350](https://github.com/rust-lang/rust-clippy/pull/7350)
 +  * Moved [`blanket_clippy_restriction_lints`] to `suspicious`
 +  * Moved [`empty_loop`] to `suspicious`
 +  * Moved [`eval_order_dependence`] to `suspicious`
 +  * Moved [`float_equality_without_abs`] to `suspicious`
 +  * Moved [`for_loops_over_fallibles`] to `suspicious`
 +  * Moved [`misrefactored_assign_op`] to `suspicious`
 +  * Moved [`mut_range_bound`] to `suspicious`
 +  * Moved [`mutable_key_type`] to `suspicious`
 +  * Moved [`suspicious_arithmetic_impl`] to `suspicious`
 +  * Moved [`suspicious_assignment_formatting`] to `suspicious`
 +  * Moved [`suspicious_else_formatting`] to `suspicious`
 +  * Moved [`suspicious_map`] to `suspicious`
 +  * Moved [`suspicious_op_assign_impl`] to `suspicious`
 +  * Moved [`suspicious_unary_op_formatting`] to `suspicious`
 +
 +### Enhancements
 +
 +* [`while_let_on_iterator`]: Now suggests `&mut iter` inside closures
 +  [#7262](https://github.com/rust-lang/rust-clippy/pull/7262)
 +* [`doc_markdown`]:
 +  * Now detects unbalanced ticks
 +    [#7357](https://github.com/rust-lang/rust-clippy/pull/7357)
 +  * Add `FreeBSD` to the default configuration as an allowed identifier
 +    [#7334](https://github.com/rust-lang/rust-clippy/pull/7334)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: Now allows wildcards for enums with unstable
 +  or hidden variants
 +  [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 +* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
 +  [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
 +* [`disallowed_names`]: Now allows disallowed names in test code
 +  [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 +* [`redundant_closure`]: Suggests `&mut` for `FnMut`
 +  [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
 +* [`disallowed_methods`], [`disallowed_types`]: The configuration values `disallowed-method` and `disallowed-type`
 +  no longer require fully qualified paths
 +  [#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
 +* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
 +  [#7396](https://github.com/rust-lang/rust-clippy/pull/7396)
 +
 +### False Positive Fixes
 +
 +* [`default_numeric_fallback`]: No longer lints on float literals as function arguments
 +  [#7446](https://github.com/rust-lang/rust-clippy/pull/7446)
 +* [`use_self`]: No longer lints on type parameters
 +  [#7288](https://github.com/rust-lang/rust-clippy/pull/7288)
 +* [`unimplemented`]: Now ignores the `assert` and `debug_assert` macros
 +  [#7439](https://github.com/rust-lang/rust-clippy/pull/7439)
 +* [`branches_sharing_code`]: Now always checks for block expressions
 +  [#7462](https://github.com/rust-lang/rust-clippy/pull/7462)
 +* [`field_reassign_with_default`]: No longer triggers in macros
 +  [#7160](https://github.com/rust-lang/rust-clippy/pull/7160)
 +* [`redundant_clone`]: No longer lints on required clones for borrowed data
 +  [#7346](https://github.com/rust-lang/rust-clippy/pull/7346)
 +* [`default_numeric_fallback`]: No longer triggers in external macros
 +  [#7325](https://github.com/rust-lang/rust-clippy/pull/7325)
 +* [`needless_bool`]: No longer lints in macros
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`useless_format`]: No longer triggers when additional text is being appended
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`assertions_on_constants`]: `cfg!(...)` is no longer considered to be a constant
 +  [#7319](https://github.com/rust-lang/rust-clippy/pull/7319)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`needless_collect`]: Now show correct lint messages for shadowed values
 +  [#7289](https://github.com/rust-lang/rust-clippy/pull/7289)
 +* [`wrong_pub_self_convention`]: The deprecated message now suggest the correct configuration value
 +  [#7382](https://github.com/rust-lang/rust-clippy/pull/7382)
 +* [`semicolon_if_nothing_returned`]: Allow missing semicolon in blocks with only one expression
 +  [#7326](https://github.com/rust-lang/rust-clippy/pull/7326)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#7470](https://github.com/rust-lang/rust-clippy/pull/7470)
 +* [`redundant_pattern_matching`]
 +  [#7471](https://github.com/rust-lang/rust-clippy/pull/7471)
 +* [`modulo_one`]
 +  [#7473](https://github.com/rust-lang/rust-clippy/pull/7473)
 +* [`use_self`]
 +  [#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
 +
 +## Rust 1.54
 +
 +Released 2021-07-29
 +
 +[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
 +
 +### New Lints
 +
 +- [`ref_binding_to_reference`]
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`needless_bitwise_bool`]
 +  [#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
 +- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
 +- [`manual_str_repeat`]
 +  [#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
 +- [`suspicious_splitn`]
 +  [#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
 +
 +### Moves and Deprecations
 +
 +- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
 +  the new `avoid-breaking-exported-api` config option (see
 +  [Enhancements](#1-54-enhancements))
 +  [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- Move [`inconsistent_struct_constructor`] to `pedantic`
 +  [#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
 +- Move [`needless_borrow`] to `style` (now warn-by-default)
 +  [#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
 +- Move [`suspicious_operation_groupings`] to `nursery`
 +  [#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
 +- Move [`semicolon_if_nothing_returned`] to `pedantic`
 +  [#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
 +
 +### Enhancements <a name="1-54-enhancements"></a>
 +
 +- [`while_let_on_iterator`]: Now also lints in nested loops
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
 +  [#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
 +- [`needless_collect`]: Now also lints on assignments with type annotations
 +  [#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
 +- [`if_then_some_else_none`]: Now works with the MSRV config
 +  [#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
 +- Add `avoid-breaking-exported-api` config option for the lints
 +  [`enum_variant_names`], [`large_types_passed_by_value`],
 +  [`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
 +  [`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
 +  this configuration option to `false` before a major release (1.0/2.0/...) to
 +  clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- [`needless_collect`]: Now lints on even more data structures
 +  [#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
 +- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
 +  attributes as sufficient documentation
 +  [#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
 +- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
 +  Now work as expected when used with `allow`
 +  [#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
 +
 +### False Positive Fixes
 +
 +- [`implicit_return`]: Now takes all diverging functions in account to avoid
 +  false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
 +  and the struct is used in the loop
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`multiple_inherent_impl`]: No longer lints with generic arguments
 +  [#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
 +- [`comparison_chain`]: No longer lints in a `const` context
 +  [#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
 +- [`while_immutable_condition`]: Fix false positive where mutation in the loop
 +  variable wasn't picked up
 +  [#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
 +- [`default_trait_access`]: No longer lints in macros
 +  [#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
 +- [`needless_question_mark`]: No longer lints when the inner value is implicitly
 +  dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
 +- [`unused_unit`]: No longer lints when multiple macro contexts are involved
 +  [#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
 +- [`eval_order_dependence`]: Fix false positive in async context
 +  [#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
 +- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
 +  type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
 +- [`wrong_self_convention`]: No longer lints in trait implementations of
 +  non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
 +- [`suboptimal_flops`]: No longer lints on `powi(2)`
 +  [#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
 +- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
 +  [#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
 +- [`option_if_let_else`]: No longer lints on `else if let` pattern
 +  [#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
 +- [`use_self`], [`useless_conversion`]: Fix false positives when generic
 +  arguments are involved
 +  [#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
 +- [`manual_unwrap_or`]: Fix false positive with deref coercion
 +  [#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
 +- [`similar_names`]: No longer lints on `wparam`/`lparam`
 +  [#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
 +- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
 +  closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
 +
 +### Suggestion Fixes/Improvements
 +
 +- [`implicit_return`]
 +  [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +    - Fix suggestion for async functions
 +    - Improve suggestion with macros
 +    - Suggest to change `break` to `return` when appropriate
 +- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`match_single_binding`]: Improve suggestion when match scrutinee has side
 +  effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
 +- [`needless_borrow`]: Now suggests to also change usage sites as needed
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
 +  buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
 +- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
 +  when a `<_ as Trait>::_` is involved
 +  [#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
 +- [`not_unsafe_ptr_arg_deref`]: Improved error message
 +  [#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
 +
 +### ICE Fixes
 +
 +- Fix ICE when running Clippy on `libstd`
 +  [#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
 +- [`implicit_return`]
 +  [#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
 +
 +## Rust 1.53
 +
 +Released 2021-06-17
 +
 +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
 +
 +### New Lints
 +
 +* [`option_filter_map`]
 +  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
 +* [`branches_sharing_code`]
 +  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
 +* [`needless_for_each`]
 +  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
 +* [`if_then_some_else_none`]
 +  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
 +* [`non_octal_unix_permissions`]
 +  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
 +* [`unnecessary_self_imports`]
 +  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
 +* [`bool_assert_comparison`]
 +  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
 +* [`cloned_instead_of_copied`]
 +  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
 +* [`flat_map_option`]
 +  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`filter_map`] lint
 +  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
 +* Move [`transmute_ptr_to_ptr`] to `pedantic`
 +  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
 +
 +### Enhancements
 +
 +* [`mem_replace_with_default`]: Also lint on common std constructors
 +  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
 +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
 +  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
 +  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
 +    * Attempt to find a common path prefix in suggestion
 +    * Don't lint on `Option` and `Result`
 +    * Consider `Self` prefix
 +* [`explicit_deref_methods`]: Also lint on chained `deref` calls
 +  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
 +* [`or_fun_call`]: Also lint on `unsafe` blocks
 +  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
 +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
 +  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
 +* [`search_is_some`]: Also check for `is_none`
 +  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
 +* [`string_lit_as_bytes`]: Also lint on `into_bytes`
 +  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
 +* [`len_without_is_empty`]: Also lint if function signatures of `len` and
 +  `is_empty` don't match
 +  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
 +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
 +  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
 +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
 +  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
 +* [`needless_return`]: Also lint in `async` functions
 +  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
 +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
 +  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
 +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
 +  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
 +
 +### False Positive Fixes
 +
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
 +* [`suspicious_map`]: No longer lints when side effects may occur inside the
 +  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
 +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
 +  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
 +* [`wrong_self_convention`]: Now respects `Copy` types
 +  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
 +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
 +  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
 +* [`map_entry`]: Better detect if the entry API can be used
 +  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`or_fun_call`]: No longer lints on some `len` function calls
 +  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
 +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
 +  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
 +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
 +  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
 +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
 +  suggesting to use `derive` instead
 +  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
 +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
 +  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
 +* [`clone_on_copy`]: Only lint when using the `Clone` trait
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`wrong_self_convention`]: No longer lints inside a trait implementation
 +  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
 +* [`redundant_clone`]: No longer lints when the cloned value is modified while
 +  the clone is in use
 +  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
 +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
 +  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
 +* [`cargo_common_metadata`]: Remove author requirement
 +  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
 +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
 +  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
 +* [`panic`]: No longer wrongfully lints on `debug_assert` with message
 +  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
 +* [`wrong_self_convention`]: No longer lints in trait implementations where no
 +  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
 +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
 +  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
 +* [`suspicious_else_formatting`]: Allow Allman style braces
 +  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
 +* [`inconsistent_struct_constructor`]: No longer lints in macros
 +  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
 +* [`single_component_path_imports`]: No longer lints on macro re-exports
 +  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`redundant_pattern_matching`]: Add a note when applying this lint would
 +  change the drop order
 +  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
 +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
 +  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
 +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
 +  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
 +* [`inconsistent_struct_constructor`]: Make lint description and message clearer
 +  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
 +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
 +  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`manual_flatten`]: Suggest to insert `copied` if necessary
 +  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
 +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
 +  when the value is from a macro call
 +  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
 +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
 +  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
 +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`manual_map`]: Fix suggestion at the end of an if chain
 +  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
 +* Fix needless parenthesis output in multiple lint suggestions
 +  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
 +* [`needless_collect`]: Better explanation in the lint message
 +  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
 +* [`useless_vec`]: Now considers mutability
 +  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
 +* [`useless_format`]: Wrap the content in braces if necessary
 +  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
 +* [`single_match`]: Don't suggest an equality check for types which don't
 +  implement `PartialEq`
 +  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
 +* [`from_over_into`]: Mention type in help message
 +  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
 +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
 +  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
 +
 +### ICE Fixes
 +
 +* [`macro_use_imports`]
 +  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
 +* [`missing_panics_doc`]
 +  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
 +* [`tabs_in_doc_comments`]
 +  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
 +* [`missing_const_for_fn`]
 +  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
 +  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
 +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
 +  deprecation warning
 +  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 +
 +## Rust 1.52
 +
 +Released 2021-05-06
 +
 +[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 +
 +### New Lints
 +
 +* [`from_str_radix_10`]
 +  [#6717](https://github.com/rust-lang/rust-clippy/pull/6717)
 +* [`implicit_clone`]
 +  [#6730](https://github.com/rust-lang/rust-clippy/pull/6730)
 +* [`semicolon_if_nothing_returned`]
 +  [#6681](https://github.com/rust-lang/rust-clippy/pull/6681)
 +* [`manual_flatten`]
 +  [#6646](https://github.com/rust-lang/rust-clippy/pull/6646)
 +* [`inconsistent_struct_constructor`]
 +  [#6769](https://github.com/rust-lang/rust-clippy/pull/6769)
 +* [`iter_count`]
 +  [#6791](https://github.com/rust-lang/rust-clippy/pull/6791)
 +* [`default_numeric_fallback`]
 +  [#6662](https://github.com/rust-lang/rust-clippy/pull/6662)
 +* [`bytes_nth`]
 +  [#6695](https://github.com/rust-lang/rust-clippy/pull/6695)
 +* [`filter_map_identity`]
 +  [#6685](https://github.com/rust-lang/rust-clippy/pull/6685)
 +* [`manual_map`]
 +  [#6573](https://github.com/rust-lang/rust-clippy/pull/6573)
 +
 +### Moves and Deprecations
 +
 +* Moved [`upper_case_acronyms`] to `pedantic`
 +  [#6775](https://github.com/rust-lang/rust-clippy/pull/6775)
 +* Moved [`manual_map`] to `nursery`
 +  [#6796](https://github.com/rust-lang/rust-clippy/pull/6796)
 +* Moved [`unnecessary_wraps`] to `pedantic`
 +  [#6765](https://github.com/rust-lang/rust-clippy/pull/6765)
 +* Moved [`trivial_regex`] to `nursery`
 +  [#6696](https://github.com/rust-lang/rust-clippy/pull/6696)
 +* Moved [`naive_bytecount`] to `pedantic`
 +  [#6825](https://github.com/rust-lang/rust-clippy/pull/6825)
 +* Moved [`upper_case_acronyms`] to `style`
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* Moved [`manual_map`] to `style`
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +
 +### Enhancements
 +
 +* [`disallowed_methods`]: Now supports functions in addition to methods
 +  [#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
 +* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
 +  trigger the lint if there is more than one uppercase character next to each other
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* [`collapsible_match`]: Now supports block comparison with different value names
 +  [#6754](https://github.com/rust-lang/rust-clippy/pull/6754)
 +* [`unnecessary_wraps`]: Will now suggest removing unnecessary wrapped return unit type, like `Option<()>`
 +  [#6665](https://github.com/rust-lang/rust-clippy/pull/6665)
 +* Improved value usage detection in closures
 +  [#6698](https://github.com/rust-lang/rust-clippy/pull/6698)
 +
 +### False Positive Fixes
 +
 +* [`use_self`]: No longer lints in macros
 +  [#6833](https://github.com/rust-lang/rust-clippy/pull/6833)
 +* [`use_self`]: Fixed multiple false positives for: generics, associated types and derive implementations
 +  [#6179](https://github.com/rust-lang/rust-clippy/pull/6179)
 +* [`missing_inline_in_public_items`]: No longer lints for procedural macros
 +  [#6814](https://github.com/rust-lang/rust-clippy/pull/6814)
 +* [`inherent_to_string`]: No longer lints on functions with function generics
 +  [#6771](https://github.com/rust-lang/rust-clippy/pull/6771)
 +* [`doc_markdown`]: Add `OpenDNS` to the default configuration as an allowed identifier
 +  [#6783](https://github.com/rust-lang/rust-clippy/pull/6783)
 +* [`missing_panics_doc`]: No longer lints on [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html)
 +  [#6700](https://github.com/rust-lang/rust-clippy/pull/6700)
 +* [`collapsible_if`]: No longer lints on if statements with attributes
 +  [#6701](https://github.com/rust-lang/rust-clippy/pull/6701)
 +* [`match_same_arms`]: Only considers empty blocks as equal if the tokens contained are the same
 +  [#6843](https://github.com/rust-lang/rust-clippy/pull/6843)
 +* [`redundant_closure`]: Now ignores macros
 +  [#6871](https://github.com/rust-lang/rust-clippy/pull/6871)
 +* [`manual_map`]: Fixed false positives when control flow statements like `return`, `break` etc. are used
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* [`vec_init_then_push`]: Fixed false positives for loops and if statements
 +  [#6697](https://github.com/rust-lang/rust-clippy/pull/6697)
 +* [`len_without_is_empty`]: Will now consider multiple impl blocks and `#[allow]` on
 +  the `len` method as well as the type definition.
 +  [#6853](https://github.com/rust-lang/rust-clippy/pull/6853)
 +* [`let_underscore_drop`]: Only lints on types which implement `Drop`
 +  [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 +* [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
 +  [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
 +* [`cargo_common_metadata`]: No longer lints if
 +  [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
 +  is defined in the manifest
 +  [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`collapsible_match`]: Fixed lint message capitalization
 +  [#6766](https://github.com/rust-lang/rust-clippy/pull/6766)
 +* [`or_fun_call`]: Improved suggestions for `or_insert(vec![])`
 +  [#6790](https://github.com/rust-lang/rust-clippy/pull/6790)
 +* [`manual_map`]: No longer expands macros in the suggestions
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* Aligned Clippy's lint messages with the rustc dev guide
 +  [#6787](https://github.com/rust-lang/rust-clippy/pull/6787)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6866](https://github.com/rust-lang/rust-clippy/pull/6866)
 +
 +### Documentation Improvements
 +
 +* [`useless_format`]: Improved the documentation example
 +  [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
 +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
 +  [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 +
 +### Others
 +* Running `cargo clippy` after `cargo check` now works as expected
 +  (`cargo clippy` and `cargo check` no longer shares the same build cache)
 +  [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 +* Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
 +  [#6834](https://github.com/rust-lang/rust-clippy/pull/6834)
 +* Extracted Clippy's `utils` module into the new `clippy_utils` crate
 +  [#6756](https://github.com/rust-lang/rust-clippy/pull/6756)
 +* Clippy lintcheck tool improvements
 +  [#6800](https://github.com/rust-lang/rust-clippy/pull/6800)
 +  [#6735](https://github.com/rust-lang/rust-clippy/pull/6735)
 +  [#6764](https://github.com/rust-lang/rust-clippy/pull/6764)
 +  [#6708](https://github.com/rust-lang/rust-clippy/pull/6708)
 +  [#6780](https://github.com/rust-lang/rust-clippy/pull/6780)
 +  [#6686](https://github.com/rust-lang/rust-clippy/pull/6686)
 +
 +## Rust 1.51
 +
 +Released 2021-03-25
 +
 +[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 +
 +### New Lints
 +
 +* [`upper_case_acronyms`]
 +  [#6475](https://github.com/rust-lang/rust-clippy/pull/6475)
 +* [`from_over_into`] [#6476](https://github.com/rust-lang/rust-clippy/pull/6476)
 +* [`case_sensitive_file_extension_comparisons`]
 +  [#6500](https://github.com/rust-lang/rust-clippy/pull/6500)
 +* [`needless_question_mark`]
 +  [#6507](https://github.com/rust-lang/rust-clippy/pull/6507)
 +* [`missing_panics_doc`]
 +  [#6523](https://github.com/rust-lang/rust-clippy/pull/6523)
 +* [`redundant_slicing`]
 +  [#6528](https://github.com/rust-lang/rust-clippy/pull/6528)
 +* [`vec_init_then_push`]
 +  [#6538](https://github.com/rust-lang/rust-clippy/pull/6538)
 +* [`ptr_as_ptr`] [#6542](https://github.com/rust-lang/rust-clippy/pull/6542)
 +* [`collapsible_else_if`] (split out from `collapsible_if`)
 +  [#6544](https://github.com/rust-lang/rust-clippy/pull/6544)
 +* [`inspect_for_each`] [#6577](https://github.com/rust-lang/rust-clippy/pull/6577)
 +* [`manual_filter_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* [`exhaustive_enums`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +* [`exhaustive_structs`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +
 +### Moves and Deprecations
 +
 +* Replace [`find_map`] with [`manual_find_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* `unknown_clippy_lints` Now integrated in the `unknown_lints` rustc lint
 +  [#6653](https://github.com/rust-lang/rust-clippy/pull/6653)
 +
 +### Enhancements
 +
 +* [`ptr_arg`] Now also suggests to use `&Path` instead of `&PathBuf`
 +  [#6506](https://github.com/rust-lang/rust-clippy/pull/6506)
 +* [`cast_ptr_alignment`] Also lint when the `pointer::cast` method is used
 +  [#6557](https://github.com/rust-lang/rust-clippy/pull/6557)
 +* [`collapsible_match`] Now also deals with `&` and `*` operators in the `match`
 +  scrutinee [#6619](https://github.com/rust-lang/rust-clippy/pull/6619)
 +
 +### False Positive Fixes
 +
 +* [`similar_names`] Ignore underscore prefixed names
 +  [#6403](https://github.com/rust-lang/rust-clippy/pull/6403)
 +* [`print_literal`] and [`write_literal`] No longer lint numeric literals
 +  [#6408](https://github.com/rust-lang/rust-clippy/pull/6408)
 +* [`large_enum_variant`] No longer lints in external macros
 +  [#6485](https://github.com/rust-lang/rust-clippy/pull/6485)
 +* [`empty_enum`] Only lint if `never_type` feature is enabled
 +  [#6513](https://github.com/rust-lang/rust-clippy/pull/6513)
 +* [`field_reassign_with_default`] No longer lints in macros
 +  [#6553](https://github.com/rust-lang/rust-clippy/pull/6553)
 +* [`size_of_in_element_count`] No longer lints when dividing by element size
 +  [#6578](https://github.com/rust-lang/rust-clippy/pull/6578)
 +* [`needless_return`] No longer lints in macros
 +  [#6586](https://github.com/rust-lang/rust-clippy/pull/6586)
 +* [`match_overlapping_arm`] No longer lint when first arm is completely included
 +  in second arm [#6603](https://github.com/rust-lang/rust-clippy/pull/6603)
 +* [`doc_markdown`] Add `WebGL` to the default configuration as an allowed
 +  identifier [#6605](https://github.com/rust-lang/rust-clippy/pull/6605)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`field_reassign_with_default`] Don't expand macro in lint suggestion
 +  [#6531](https://github.com/rust-lang/rust-clippy/pull/6531)
 +* [`match_like_matches_macro`] Strip references in suggestion
 +  [#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
 +* [`single_match`] Suggest `if` over `if let` when possible
 +  [#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
 +* `ref_in_deref` Use parentheses correctly in suggestion
 +  [#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
 +* [`stable_sort_primitive`] Clarify error message
 +  [#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6582](https://github.com/rust-lang/rust-clippy/pull/6582)
 +
 +### Documentation Improvements
 +
 +* Improve search performance on the Clippy website and make it possible to
 +  directly search for lints on the GitHub issue tracker
 +  [#6483](https://github.com/rust-lang/rust-clippy/pull/6483)
 +* Clean up `README.md` by removing outdated paragraph
 +  [#6488](https://github.com/rust-lang/rust-clippy/pull/6488)
 +* [`await_holding_refcell_ref`] and [`await_holding_lock`]
 +  [#6585](https://github.com/rust-lang/rust-clippy/pull/6585)
 +* [`as_conversions`] [#6608](https://github.com/rust-lang/rust-clippy/pull/6608)
 +
 +### Others
 +
 +* Clippy now has a [Roadmap] for 2021. If you like to get involved in a bigger
 +  project, take a look at the [Roadmap project page]. All issues listed there
 +  are actively mentored
 +  [#6462](https://github.com/rust-lang/rust-clippy/pull/6462)
 +* The Clippy version number now corresponds to the Rust version number
 +  [#6526](https://github.com/rust-lang/rust-clippy/pull/6526)
 +* Fix oversight which caused Clippy to lint deps in some environments, where
 +  `CLIPPY_TESTS=true` was set somewhere
 +  [#6575](https://github.com/rust-lang/rust-clippy/pull/6575)
 +* Add `cargo dev-lintcheck` tool to the Clippy Dev Tool
 +  [#6469](https://github.com/rust-lang/rust-clippy/pull/6469)
 +
 +[Roadmap]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/proposals/roadmap-2021.md
 +[Roadmap project page]: https://github.com/rust-lang/rust-clippy/projects/3
 +
 +## Rust 1.50
 +
 +Released 2021-02-11
 +
 +[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
 +
 +### New Lints
 +
 +* [`suspicious_operation_groupings`] [#6086](https://github.com/rust-lang/rust-clippy/pull/6086)
 +* [`size_of_in_element_count`] [#6394](https://github.com/rust-lang/rust-clippy/pull/6394)
 +* [`unnecessary_wraps`] [#6070](https://github.com/rust-lang/rust-clippy/pull/6070)
 +* [`let_underscore_drop`] [#6305](https://github.com/rust-lang/rust-clippy/pull/6305)
 +* [`collapsible_match`] [#6402](https://github.com/rust-lang/rust-clippy/pull/6402)
 +* [`redundant_else`] [#6330](https://github.com/rust-lang/rust-clippy/pull/6330)
 +* [`zero_sized_map_values`] [#6218](https://github.com/rust-lang/rust-clippy/pull/6218)
 +* [`print_stderr`] [#6367](https://github.com/rust-lang/rust-clippy/pull/6367)
 +* [`string_from_utf8_as_bytes`] [#6134](https://github.com/rust-lang/rust-clippy/pull/6134)
 +
 +### Moves and Deprecations
 +
 +* Previously deprecated [`str_to_string`] and [`string_to_string`] have been un-deprecated
 +  as `restriction` lints [#6333](https://github.com/rust-lang/rust-clippy/pull/6333)
 +* Deprecate `panic_params` lint. This is now available in rustc as `non_fmt_panics`
 +  [#6351](https://github.com/rust-lang/rust-clippy/pull/6351)
 +* Move [`map_err_ignore`] to `restriction`
 +  [#6416](https://github.com/rust-lang/rust-clippy/pull/6416)
 +* Move [`await_holding_refcell_ref`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +* Move [`await_holding_lock`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +
 +### Enhancements
 +
 +* Add the `unreadable-literal-lint-fractions` configuration to disable
 +  the `unreadable_literal` lint for fractions
 +  [#6421](https://github.com/rust-lang/rust-clippy/pull/6421)
 +* [`clone_on_copy`]: Now shows the type in the lint message
 +  [#6443](https://github.com/rust-lang/rust-clippy/pull/6443)
 +* [`redundant_pattern_matching`]: Now also lints on `std::task::Poll`
 +  [#6339](https://github.com/rust-lang/rust-clippy/pull/6339)
 +* [`redundant_pattern_matching`]: Additionally also lints on `std::net::IpAddr`
 +  [#6377](https://github.com/rust-lang/rust-clippy/pull/6377)
 +* [`search_is_some`]: Now suggests `contains` instead of `find(foo).is_some()`
 +  [#6119](https://github.com/rust-lang/rust-clippy/pull/6119)
 +* [`clone_double_ref`]: Now prints the reference type in the lint message
 +  [#6442](https://github.com/rust-lang/rust-clippy/pull/6442)
 +* [`modulo_one`]: Now also lints on -1.
 +  [#6360](https://github.com/rust-lang/rust-clippy/pull/6360)
 +* [`empty_loop`]: Now lints no_std crates, too
 +  [#6205](https://github.com/rust-lang/rust-clippy/pull/6205)
 +* [`or_fun_call`]: Now also lints when indexing `HashMap` or `BTreeMap`
 +  [#6267](https://github.com/rust-lang/rust-clippy/pull/6267)
 +* [`wrong_self_convention`]: Now also lints in trait definitions
 +  [#6316](https://github.com/rust-lang/rust-clippy/pull/6316)
 +* [`needless_borrow`]: Print the type in the lint message
 +  [#6449](https://github.com/rust-lang/rust-clippy/pull/6449)
 +
 +[msrv_readme]: https://github.com/rust-lang/rust-clippy#specifying-the-minimum-supported-rust-version
 +
 +### False Positive Fixes
 +
 +* [`manual_range_contains`]: No longer lints in `const fn`
 +  [#6382](https://github.com/rust-lang/rust-clippy/pull/6382)
 +* [`unnecessary_lazy_evaluations`]: No longer lints if closure argument is used
 +  [#6370](https://github.com/rust-lang/rust-clippy/pull/6370)
 +* [`match_single_binding`]: Now ignores cases with `#[cfg()]` macros
 +  [#6435](https://github.com/rust-lang/rust-clippy/pull/6435)
 +* [`match_like_matches_macro`]: No longer lints on arms with attributes
 +  [#6290](https://github.com/rust-lang/rust-clippy/pull/6290)
 +* [`map_clone`]: No longer lints with deref and clone
 +  [#6269](https://github.com/rust-lang/rust-clippy/pull/6269)
 +* [`map_clone`]: No longer lints in the case of &mut
 +  [#6301](https://github.com/rust-lang/rust-clippy/pull/6301)
 +* [`needless_update`]: Now ignores `non_exhaustive` structs
 +  [#6464](https://github.com/rust-lang/rust-clippy/pull/6464)
 +* [`needless_collect`]: No longer lints when a collect is needed multiple times
 +  [#6313](https://github.com/rust-lang/rust-clippy/pull/6313)
 +* [`unnecessary_cast`] No longer lints cfg-dependent types
 +  [#6369](https://github.com/rust-lang/rust-clippy/pull/6369)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
 +  Both now ignore enums with frozen variants
 +  [#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
 +* [`field_reassign_with_default`] No longer lint for private fields
 +  [#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
 +
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`vec_box`]: Provide correct type scope suggestion
 +  [#6271](https://github.com/rust-lang/rust-clippy/pull/6271)
 +* [`manual_range_contains`]: Give correct suggestion when using floats
 +  [#6320](https://github.com/rust-lang/rust-clippy/pull/6320)
 +* [`unnecessary_lazy_evaluations`]: Don't always mark suggestion as MachineApplicable
 +  [#6272](https://github.com/rust-lang/rust-clippy/pull/6272)
 +* [`manual_async_fn`]: Improve suggestion formatting
 +  [#6294](https://github.com/rust-lang/rust-clippy/pull/6294)
 +* [`unnecessary_cast`]: Fix incorrectly formatted float literal suggestion
 +  [#6362](https://github.com/rust-lang/rust-clippy/pull/6362)
 +
 +### ICE Fixes
 +
 +* Fix a crash in [`from_iter_instead_of_collect`]
 +  [#6304](https://github.com/rust-lang/rust-clippy/pull/6304)
 +* Fix a silent crash when parsing doc comments in [`needless_doctest_main`]
 +  [#6458](https://github.com/rust-lang/rust-clippy/pull/6458)
 +
 +### Documentation Improvements
 +
 +* The lint website search has been improved ([#6477](https://github.com/rust-lang/rust-clippy/pull/6477)):
 +  * Searching for lints with dashes and spaces is possible now. For example
 +    `missing-errors-doc` and `missing errors doc` are now valid aliases for lint names
 +  * Improved fuzzy search in lint descriptions
 +* Various README improvements
 +  [#6287](https://github.com/rust-lang/rust-clippy/pull/6287)
 +* Add known problems to [`comparison_chain`] documentation
 +  [#6390](https://github.com/rust-lang/rust-clippy/pull/6390)
 +* Fix example used in [`cargo_common_metadata`]
 +  [#6293](https://github.com/rust-lang/rust-clippy/pull/6293)
 +* Improve [`map_clone`] documentation
 +  [#6340](https://github.com/rust-lang/rust-clippy/pull/6340)
 +
 +### Others
 +
 +* You can now tell Clippy about the MSRV your project supports. Please refer to
 +  the specific README section to learn more about MSRV support [here][msrv_readme]
 +  [#6201](https://github.com/rust-lang/rust-clippy/pull/6201)
 +* Add `--no-deps` option to avoid running on path dependencies in workspaces
 +  [#6188](https://github.com/rust-lang/rust-clippy/pull/6188)
 +
 +## Rust 1.49
 +
 +Released 2020-12-31
 +
 +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 +
 +### New Lints
 +
 +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
 +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
 +* [`disallowed_methods`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
 +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
 +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
 +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
 +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
 +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
 +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
 +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
 +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
 +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
 +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
 +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
 +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
 +
 +### Moves and Deprecations
 +
 +* Rename `single_char_push_str` to [`single_char_add_str`]
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* Rename `zero_width_space` to [`invisible_characters`]
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* Deprecate `drop_bounds` (uplifted)
 +  [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
 +* Move [`string_lit_as_bytes`] to `nursery`
 +  [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
 +* Move [`rc_buffer`] to `restriction`
 +  [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
 +
 +### Enhancements
 +
 +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
 +  reliable suggestion)
 +  [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
 +* [`single_char_add_str`]: Also lint on `String::insert_str`
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* [`eq_op`]: Also lint on the `assert_*!` macro family
 +  [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
 +* [`items_after_statements`]: Also lint in local macro expansions
 +  [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
 +* [`unnecessary_cast`]: Also lint casts on integer and float literals
 +  [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
 +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
 +  [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
 +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
 +  [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
 +* [`integer_arithmetic`]: Better handle `/` an `%` operators
 +  [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
 +
 +### False Positive Fixes
 +
 +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
 +  lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
 +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
 +  is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
 +* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
 +  [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
 +* [`needless_range_loop`]: No longer lints, when the iterable is used in the
 +  range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
 +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
 +  [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
 +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
 +  float (e.g. `713.32_64`)
 +  [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
 +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
 +  [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
 +* [`boxed_local`]: No longer lints on `extern fn` arguments
 +  [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
 +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
 +  clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
 +  [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
 +* [`needless_arbitrary_self_type`]: Correctly handle expanded code
 +  [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
 +* [`useless_format`]: Preserve raw strings in suggestion
 +  [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
 +* [`empty_loop`]: Suggest alternatives
 +  [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`borrowed_box`]: Correctly add parentheses in suggestion
 +  [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
 +* [`unused_unit`]: Improve suggestion formatting
 +  [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
 +
 +### Documentation Improvements
 +
 +* Some doc improvements:
 +    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
 +    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`doc_markdown`]: Document problematic link text style
 +  [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 +
 +## Rust 1.48
 +
 +Released 2020-11-19
 +
 +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 +
 +### New lints
 +
 +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
 +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
 +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
 +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 +* `to_string_in_display` [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
 +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`verbose_bit_mask`] to pedantic
 +  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
 +
 +### Enhancements
 +
 +* Extend [`precedence`] to handle chains of methods combined with unary negation
 +  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
 +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
 +  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
 +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
 +  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
 +* `invalid_atomic_ordering`: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
 +  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
 +* Avoid [`redundant_pattern_matching`] triggering in macros
 +  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
 +* [`option_if_let_else`]: distinguish pure from impure `else` expressions
 +  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
 +* [`needless_doctest_main`]: parse doctests instead of using textual search
 +  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
 +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
 +  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
 +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
 +  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
 +
 +### False Positive Fixes
 +
 +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
 +  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
 +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
 +  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
 +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
 +  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
 +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
 +  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
 +* [`doc_markdown`]: allow using "GraphQL" without backticks
 +  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
 +* `to_string_in_display`: avoid linting when calling `to_string()` on anything that is not `self`
 +  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
 +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
 +  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
 +* [`should_implement_trait`]: ignore methods with lifetime parameters
 +  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
 +* [`needless_return`]: avoid linting if a temporary borrows a local variable
 +  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
 +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
 +  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
 +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
 +  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
 +  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
 +  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
 +* [`useless_conversion`]: show the type in the error message
 +  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
 +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
 +  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
 +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
 +  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
 +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
 +  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
 +* [`collapsible_if`]: don't use expanded code in the suggestion
 +  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
 +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
 +  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
 +* [`unit_arg`]: improve the readability of the suggestion
 +  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
 +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
 +  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
 +* Show line count and max lines in [`too_many_lines`] lint message
 +  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
 +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
 +  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
 +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
 +  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
 +* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
 +  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
 +* Make lint messages adhere to rustc dev guide conventions
 +  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`repeat_once`]
 +  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
 +
 +### Documentation Improvements
 +
 +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
 +  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
 +* [`unnecessary_mut_passed`]: fix typo
 +  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
 +* Add example of false positive to [`ptr_arg`] docs.
 +  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
 +* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
 +  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 +
 +## Rust 1.47
 +
 +Released 2020-10-08
 +
 +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 +
 +### New lints
 +
 +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
 +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
 +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
 +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
 +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
 +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
 +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
 +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
 +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
 +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
 +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
 +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`regex_macro`] lint
 +  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
 +* Move [`range_minus_one`] to `pedantic`
 +  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
 +
 +### Enhancements
 +
 +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
 +  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
 +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
 +  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
 +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
 +  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
 +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
 +  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
 +* Make it possible to allow [`unsafe_derive_deserialize`]
 +  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
 +* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
 +  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
 +* Make [`clone_on_copy`] suggestion machine applicable
 +  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
 +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +
 +### False Positive Fixes
 +
 +* Avoid triggering [`or_fun_call`] with const fns that take no arguments
 +  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
 +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
 +  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
 +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
 +  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
 +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
 +  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
 +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
 +  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
 +* Avoid linting if key borrows in [`unnecessary_sort_by`]
 +  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
 +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
 +  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
 +* Take input lifetimes into account in `manual_async_fn`
 +  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
 +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
 +  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
 +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
 +  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
 +  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
 +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
 +  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
 +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
 +  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
 +* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
 +  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
 +* Add suggestion for [`iter_skip_next`]
 +  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
 +* Improve [`collapsible_if`] fix suggestion
 +  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused by [`needless_collect`]
 +  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
 +* Fix ICE caused by [`unnested_or_patterns`]
 +  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
 +
 +### Documentation Improvements
 +
 +* Fix grammar of [`await_holding_lock`] documentation
 +  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
 +
 +### Others
 +
 +* Make lints adhere to the rustc dev guide
 +  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 +
 +## Rust 1.46
 +
 +Released 2020-08-27
 +
 +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 +
 +### New lints
 +
 +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
 +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
 +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
 +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
 +
 +### Moves and Deprecations
 +
 +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
 +
 +### Enhancements
 +
 +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
 +
 +### False Positive Fixes
 +
 +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
 +  [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
 +* [`let_and_return`]: Don't lint if a temporary borrow is involved
 +  [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
 +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
 +  [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 +* [`if_same_then_else`]: Don't assume multiplication is always commutative
 +  [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
 +* [`disallowed_names`]: Remove `bar` from the default configuration
 +  [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
 +  [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
 +  [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
 +* Add auto applicable suggestion to [`macro_use_imports`]
 +  [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
 +
 +### ICE Fixes
 +
 +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
 +
 +### Documentation Improvements
 +
 +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
 +
 +### Others
 +
 +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
 +  into `rustc` and passes all the given arguments to `rustc`. This is especially
 +  useful for tools that need the `rustc` version Clippy was compiled with,
 +  instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
 +  print the output of `rustc --version`.
 +  [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
 +* New issue templates now make it easier to complain if Clippy is too annoying
 +  or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
 +
 +## Rust 1.45
 +
 +Released 2020-07-16
 +
 +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 +
 +### New lints
 +
 +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
 +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
 +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
 +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
 +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
 +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
 +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
 +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
 +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
 +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
 +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
 +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
 +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
 +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +
 +### Enhancements
 +
 +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
 +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
 +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
 +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
 +
 +### False Positive Fixes
 +
 +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
 +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
 +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
 +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
 +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
 +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
 +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
 +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
 +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
 +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
 +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
 +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
 +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
 +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
 +
 +### Suggestion Improvements
 +
 +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
 +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
 +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
 +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
 +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
 +
 +### Documentation
 +
 +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
 +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 +
 +## Rust 1.44
 +
 +Released 2020-06-04
 +
 +[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 +
 +### New lints
 +
 +* [`explicit_deref_methods`] [#5226](https://github.com/rust-lang/rust-clippy/pull/5226)
 +* [`implicit_saturating_sub`] [#5427](https://github.com/rust-lang/rust-clippy/pull/5427)
 +* [`macro_use_imports`] [#5230](https://github.com/rust-lang/rust-clippy/pull/5230)
 +* [`verbose_file_reads`] [#5272](https://github.com/rust-lang/rust-clippy/pull/5272)
 +* [`future_not_send`] [#5423](https://github.com/rust-lang/rust-clippy/pull/5423)
 +* [`redundant_pub_crate`] [#5319](https://github.com/rust-lang/rust-clippy/pull/5319)
 +* [`large_const_arrays`] [#5248](https://github.com/rust-lang/rust-clippy/pull/5248)
 +* [`result_map_or_into_option`] [#5415](https://github.com/rust-lang/rust-clippy/pull/5415)
 +* [`redundant_allocation`] [#5349](https://github.com/rust-lang/rust-clippy/pull/5349)
 +* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
 +* Move [`cognitive_complexity`] to nursery [#5428](https://github.com/rust-lang/rust-clippy/pull/5428)
 +* Move [`useless_transmute`] to nursery [#5364](https://github.com/rust-lang/rust-clippy/pull/5364)
 +* Downgrade [`inefficient_to_string`] to pedantic [#5412](https://github.com/rust-lang/rust-clippy/pull/5412)
 +* Downgrade [`option_option`] to pedantic [#5401](https://github.com/rust-lang/rust-clippy/pull/5401)
 +* Downgrade [`unreadable_literal`] to pedantic [#5419](https://github.com/rust-lang/rust-clippy/pull/5419)
 +* Downgrade [`let_unit_value`] to pedantic [#5409](https://github.com/rust-lang/rust-clippy/pull/5409)
 +* Downgrade [`trivially_copy_pass_by_ref`] to pedantic [#5410](https://github.com/rust-lang/rust-clippy/pull/5410)
 +* Downgrade [`implicit_hasher`] to pedantic [#5411](https://github.com/rust-lang/rust-clippy/pull/5411)
 +
 +### Enhancements
 +
 +* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
 +  auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 +* Make [`redundant_clone`] also trigger on cases where the cloned value is not
 +  consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
 +* Expand [`integer_arithmetic`] to also disallow bit-shifting [#5430](https://github.com/rust-lang/rust-clippy/pull/5430)
 +* [`option_as_ref_deref`] now detects more deref cases [#5425](https://github.com/rust-lang/rust-clippy/pull/5425)
 +* [`large_enum_variant`] now report the sizes of the largest and second-largest variants [#5466](https://github.com/rust-lang/rust-clippy/pull/5466)
 +* [`bool_comparison`] now also checks for inequality comparisons that can be
 +  written more concisely [#5365](https://github.com/rust-lang/rust-clippy/pull/5365)
 +* Expand [`clone_on_copy`] to work in method call arguments as well [#5441](https://github.com/rust-lang/rust-clippy/pull/5441)
 +* [`redundant_pattern_matching`] now also handles `while let` [#5483](https://github.com/rust-lang/rust-clippy/pull/5483)
 +* [`integer_arithmetic`] now also lints references of integers [#5329](https://github.com/rust-lang/rust-clippy/pull/5329)
 +* Expand [`float_cmp_const`] to also work on arrays [#5345](https://github.com/rust-lang/rust-clippy/pull/5345)
 +* Trigger [`map_flatten`] when map is called on an `Option` [#5473](https://github.com/rust-lang/rust-clippy/pull/5473)
 +
 +### False Positive Fixes
 +
 +* [`many_single_char_names`] [#5468](https://github.com/rust-lang/rust-clippy/pull/5468)
 +* [`should_implement_trait`] [#5437](https://github.com/rust-lang/rust-clippy/pull/5437)
 +* [`unused_self`] [#5387](https://github.com/rust-lang/rust-clippy/pull/5387)
 +* [`redundant_clone`] [#5453](https://github.com/rust-lang/rust-clippy/pull/5453)
 +* [`precedence`] [#5445](https://github.com/rust-lang/rust-clippy/pull/5445)
 +* [`suspicious_op_assign_impl`] [#5424](https://github.com/rust-lang/rust-clippy/pull/5424)
 +* [`needless_lifetimes`] [#5293](https://github.com/rust-lang/rust-clippy/pull/5293)
 +* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 +* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 +
 +
 +### Suggestion Improvements
 +
 +* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
 +* Improve the suggested placeholder in [`option_map_unit_fn`] [#5292](https://github.com/rust-lang/rust-clippy/pull/5292)
 +* Improve suggestion for [`match_single_binding`] when triggered inside a closure [#5350](https://github.com/rust-lang/rust-clippy/pull/5350)
 +
 +### ICE Fixes
 +
 +* Handle the unstable `trivial_bounds` feature [#5296](https://github.com/rust-lang/rust-clippy/pull/5296)
 +* `shadow_*` lints [#5297](https://github.com/rust-lang/rust-clippy/pull/5297)
 +
 +### Documentation
 +
 +* Fix documentation generation for configurable lints [#5353](https://github.com/rust-lang/rust-clippy/pull/5353)
 +* Update documentation for [`new_ret_no_self`] [#5448](https://github.com/rust-lang/rust-clippy/pull/5448)
 +* The documentation for [`option_option`] now suggest using a tri-state enum [#5403](https://github.com/rust-lang/rust-clippy/pull/5403)
 +* Fix bit mask example in [`verbose_bit_mask`] documentation [#5454](https://github.com/rust-lang/rust-clippy/pull/5454)
 +* [`wildcard_imports`] documentation now mentions that `use ...::prelude::*` is
 +  not linted [#5312](https://github.com/rust-lang/rust-clippy/pull/5312)
 +
 +## Rust 1.43
 +
 +Released 2020-04-23
 +
 +[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 +
 +### New lints
 +
 +* [`imprecise_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`suboptimal_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`wildcard_imports`] [#5029](https://github.com/rust-lang/rust-clippy/pull/5029)
 +* [`single_component_path_imports`] [#5058](https://github.com/rust-lang/rust-clippy/pull/5058)
 +* [`match_single_binding`] [#5061](https://github.com/rust-lang/rust-clippy/pull/5061)
 +* [`let_underscore_lock`] [#5101](https://github.com/rust-lang/rust-clippy/pull/5101)
 +* [`struct_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`fn_params_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`option_env_unwrap`] [#5148](https://github.com/rust-lang/rust-clippy/pull/5148)
 +* [`lossy_float_literal`] [#5202](https://github.com/rust-lang/rust-clippy/pull/5202)
 +* [`rest_pat_in_fully_bound_structs`] [#5258](https://github.com/rust-lang/rust-clippy/pull/5258)
 +
 +### Moves and Deprecations
 +
 +* Move [`unneeded_field_pattern`] to pedantic group [#5200](https://github.com/rust-lang/rust-clippy/pull/5200)
 +
 +### Enhancements
 +
 +* Make [`missing_errors_doc`] lint also trigger on `async` functions
 +  [#5181](https://github.com/rust-lang/rust-clippy/pull/5181)
 +* Add more constants to [`approx_constant`] [#5193](https://github.com/rust-lang/rust-clippy/pull/5193)
 +* Extend [`question_mark`] lint [#5266](https://github.com/rust-lang/rust-clippy/pull/5266)
 +
 +### False Positive Fixes
 +
 +* [`use_debug`] [#5047](https://github.com/rust-lang/rust-clippy/pull/5047)
 +* [`unnecessary_unwrap`] [#5132](https://github.com/rust-lang/rust-clippy/pull/5132)
 +* [`zero_prefixed_literal`] [#5170](https://github.com/rust-lang/rust-clippy/pull/5170)
 +* [`missing_const_for_fn`] [#5216](https://github.com/rust-lang/rust-clippy/pull/5216)
 +
 +### Suggestion Improvements
 +
 +* Improve suggestion when blocks of code are suggested [#5134](https://github.com/rust-lang/rust-clippy/pull/5134)
 +
 +### ICE Fixes
 +
 +* `misc_early` lints [#5129](https://github.com/rust-lang/rust-clippy/pull/5129)
 +* [`missing_errors_doc`] [#5213](https://github.com/rust-lang/rust-clippy/pull/5213)
 +* Fix ICE when evaluating `usize`s [#5256](https://github.com/rust-lang/rust-clippy/pull/5256)
 +
 +### Documentation
 +
 +* Improve documentation of [`iter_nth_zero`]
 +* Add documentation pages for stable releases [#5171](https://github.com/rust-lang/rust-clippy/pull/5171)
 +
 +### Others
 +
 +* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 +
 +
 +## Rust 1.42
 +
 +Released 2020-03-12
 +
 +[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206)
 +
 +### New lints
 +
 +* [`filetype_is_file`] [#4543](https://github.com/rust-lang/rust-clippy/pull/4543)
 +* [`let_underscore_must_use`] [#4823](https://github.com/rust-lang/rust-clippy/pull/4823)
 +* [`modulo_arithmetic`] [#4867](https://github.com/rust-lang/rust-clippy/pull/4867)
 +* [`mem_replace_with_default`] [#4881](https://github.com/rust-lang/rust-clippy/pull/4881)
 +* [`mutable_key_type`] [#4885](https://github.com/rust-lang/rust-clippy/pull/4885)
 +* [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945)
 +* [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960)
 +* [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966)
 +* `invalid_atomic_ordering` [#4999](https://github.com/rust-lang/rust-clippy/pull/4999)
 +* [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067)
 +
 +### Moves and Deprecations
 +
 +* Move [`transmute_float_to_int`] from nursery to complexity group
 +  [#5015](https://github.com/rust-lang/rust-clippy/pull/5015)
 +* Move [`range_plus_one`] to pedantic group [#5057](https://github.com/rust-lang/rust-clippy/pull/5057)
 +* Move [`debug_assert_with_mut_call`] to nursery group [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Deprecate `unused_label` [#4930](https://github.com/rust-lang/rust-clippy/pull/4930)
 +
 +### Enhancements
 +
 +* Lint vectored IO in [`unused_io_amount`] [#5027](https://github.com/rust-lang/rust-clippy/pull/5027)
 +* Make [`vec_box`] configurable by adding a size threshold [#5081](https://github.com/rust-lang/rust-clippy/pull/5081)
 +* Also lint constants in [`cmp_nan`] [#4910](https://github.com/rust-lang/rust-clippy/pull/4910)
 +* Fix false negative in [`expect_fun_call`] [#4915](https://github.com/rust-lang/rust-clippy/pull/4915)
 +* Fix false negative in [`redundant_clone`] [#5017](https://github.com/rust-lang/rust-clippy/pull/5017)
 +
 +### False Positive Fixes
 +
 +* [`map_clone`] [#4937](https://github.com/rust-lang/rust-clippy/pull/4937)
 +* [`replace_consts`] [#4977](https://github.com/rust-lang/rust-clippy/pull/4977)
 +* [`let_and_return`] [#5008](https://github.com/rust-lang/rust-clippy/pull/5008)
 +* [`eq_op`] [#5079](https://github.com/rust-lang/rust-clippy/pull/5079)
 +* [`possible_missing_comma`] [#5083](https://github.com/rust-lang/rust-clippy/pull/5083)
 +* [`debug_assert_with_mut_call`] [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Don't trigger [`let_underscore_must_use`] in external macros
 +  [#5082](https://github.com/rust-lang/rust-clippy/pull/5082)
 +* Don't trigger [`empty_loop`] in `no_std` crates [#5086](https://github.com/rust-lang/rust-clippy/pull/5086)
 +
 +### Suggestion Improvements
 +
 +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634)
 +* [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934)
 +* [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935)
 +* [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956)
 +* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
 +* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
 +* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
 +* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
 +
 +### ICE fixes
 +
 +* [`unsound_collection_transmute`] [#4975](https://github.com/rust-lang/rust-clippy/pull/4975)
 +
 +### Documentation
 +
 +* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 +
 +
 +## Rust 1.41
 +
 +Released 2020-01-30
 +
 +[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7)
 +
 +* New Lints:
 +  * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
 +  * [`to_digit_is_some`] [#4801](https://github.com/rust-lang/rust-clippy/pull/4801)
 +  * [`tabs_in_doc_comments`] [#4806](https://github.com/rust-lang/rust-clippy/pull/4806)
 +  * [`large_stack_arrays`] [#4807](https://github.com/rust-lang/rust-clippy/pull/4807)
 +  * [`same_functions_in_if_condition`] [#4814](https://github.com/rust-lang/rust-clippy/pull/4814)
 +  * [`zst_offset`] [#4816](https://github.com/rust-lang/rust-clippy/pull/4816)
 +  * [`as_conversions`] [#4821](https://github.com/rust-lang/rust-clippy/pull/4821)
 +  * [`missing_errors_doc`] [#4884](https://github.com/rust-lang/rust-clippy/pull/4884)
 +  * [`transmute_float_to_int`] [#4889](https://github.com/rust-lang/rust-clippy/pull/4889)
 +* Remove plugin interface, see
 +  [Inside Rust Blog](https://blog.rust-lang.org/inside-rust/2019/11/04/Clippy-removes-plugin-interface.html) for
 +  details [#4714](https://github.com/rust-lang/rust-clippy/pull/4714)
 +* Move [`use_self`] to nursery group [#4863](https://github.com/rust-lang/rust-clippy/pull/4863)
 +* Deprecate `into_iter_on_array` [#4788](https://github.com/rust-lang/rust-clippy/pull/4788)
 +* Expand [`string_lit_as_bytes`] to also trigger when literal has escapes
 +  [#4808](https://github.com/rust-lang/rust-clippy/pull/4808)
 +* Fix false positive in `comparison_chain` [#4842](https://github.com/rust-lang/rust-clippy/pull/4842)
 +* Fix false positive in `while_immutable_condition` [#4730](https://github.com/rust-lang/rust-clippy/pull/4730)
 +* Fix false positive in `explicit_counter_loop` [#4803](https://github.com/rust-lang/rust-clippy/pull/4803)
 +* Fix false positive in `must_use_candidate` [#4794](https://github.com/rust-lang/rust-clippy/pull/4794)
 +* Fix false positive in `print_with_newline` and `write_with_newline`
 +  [#4769](https://github.com/rust-lang/rust-clippy/pull/4769)
 +* Fix false positive in `derive_hash_xor_eq` [#4766](https://github.com/rust-lang/rust-clippy/pull/4766)
 +* Fix false positive in `missing_inline_in_public_items` [#4870](https://github.com/rust-lang/rust-clippy/pull/4870)
 +* Fix false positive in `string_add` [#4880](https://github.com/rust-lang/rust-clippy/pull/4880)
 +* Fix false positive in `float_arithmetic` [#4851](https://github.com/rust-lang/rust-clippy/pull/4851)
 +* Fix false positive in `cast_sign_loss` [#4883](https://github.com/rust-lang/rust-clippy/pull/4883)
 +* Fix false positive in `manual_swap` [#4877](https://github.com/rust-lang/rust-clippy/pull/4877)
 +* Fix ICEs occurring while checking some block expressions [#4772](https://github.com/rust-lang/rust-clippy/pull/4772)
 +* Fix ICE in `use_self` [#4776](https://github.com/rust-lang/rust-clippy/pull/4776)
 +* Fix ICEs related to `const_generics` [#4780](https://github.com/rust-lang/rust-clippy/pull/4780)
 +* Display help when running `clippy-driver` without arguments, instead of ICEing
 +  [#4810](https://github.com/rust-lang/rust-clippy/pull/4810)
 +* Clippy has its own ICE message now [#4588](https://github.com/rust-lang/rust-clippy/pull/4588)
 +* Show deprecated lints in the documentation again [#4757](https://github.com/rust-lang/rust-clippy/pull/4757)
 +* Improve Documentation by adding positive examples to some lints
 +  [#4832](https://github.com/rust-lang/rust-clippy/pull/4832)
 +
 +## Rust 1.40
 +
 +Released 2019-12-19
 +
 +[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb)
 +
 +* New Lints:
 +  * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
 +  * [`needless_doctest_main`] [#4603](https://github.com/rust-lang/rust-clippy/pull/4603)
 +  * [`suspicious_unary_op_formatting`] [#4615](https://github.com/rust-lang/rust-clippy/pull/4615)
 +  * [`debug_assert_with_mut_call`] [#4680](https://github.com/rust-lang/rust-clippy/pull/4680)
 +  * [`unused_self`] [#4619](https://github.com/rust-lang/rust-clippy/pull/4619)
 +  * [`inefficient_to_string`] [#4683](https://github.com/rust-lang/rust-clippy/pull/4683)
 +  * [`must_use_unit`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`must_use_candidate`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`double_must_use`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`comparison_chain`] [#4569](https://github.com/rust-lang/rust-clippy/pull/4569)
 +  * [`unsound_collection_transmute`] [#4592](https://github.com/rust-lang/rust-clippy/pull/4592)
 +  * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +* Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736)
 +* Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613)
 +* Expand `integer_arithmetic` to also detect mutating arithmetic like `+=` [#4585](https://github.com/rust-lang/rust-clippy/pull/4585)
 +* Fix false positive in `nonminimal_bool` [#4568](https://github.com/rust-lang/rust-clippy/pull/4568)
 +* Fix false positive in `missing_safety_doc` [#4611](https://github.com/rust-lang/rust-clippy/pull/4611)
 +* Fix false positive in `cast_sign_loss` [#4614](https://github.com/rust-lang/rust-clippy/pull/4614)
 +* Fix false positive in `redundant_clone` [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Fix false positive in `try_err` [#4721](https://github.com/rust-lang/rust-clippy/pull/4721)
 +* Fix false positive in `toplevel_ref_arg` [#4570](https://github.com/rust-lang/rust-clippy/pull/4570)
 +* Fix false positive in `multiple_inherent_impl` [#4593](https://github.com/rust-lang/rust-clippy/pull/4593)
 +* Improve more suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4575](https://github.com/rust-lang/rust-clippy/pull/4575)
 +* Improve suggestion for `zero_ptr` [#4599](https://github.com/rust-lang/rust-clippy/pull/4599)
 +* Improve suggestion for `explicit_counter_loop` [#4691](https://github.com/rust-lang/rust-clippy/pull/4691)
 +* Improve suggestion for `mul_add` [#4602](https://github.com/rust-lang/rust-clippy/pull/4602)
 +* Improve suggestion for `assertions_on_constants` [#4635](https://github.com/rust-lang/rust-clippy/pull/4635)
 +* Fix ICE in `use_self` [#4671](https://github.com/rust-lang/rust-clippy/pull/4671)
 +* Fix ICE when encountering const casts [#4590](https://github.com/rust-lang/rust-clippy/pull/4590)
 +
 +## Rust 1.39
 +
 +Released 2019-11-07
 +
 +[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b)
 +
 +* New Lints:
 +  * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
 +  * [`flat_map_identity`] [#4231](https://github.com/rust-lang/rust-clippy/pull/4231)
 +  * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535)
 +  * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511)
 +  * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394)
 +  * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386)
 +  * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498)
 +* Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348)
 +* Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403)
 +* Move `cast_lossless` to pedantic group [#4539](https://github.com/rust-lang/rust-clippy/pull/4539)
 +* `temporary_cstring_as_ptr` now catches more cases [#4425](https://github.com/rust-lang/rust-clippy/pull/4425)
 +* `use_self` now works in constructors, too [#4525](https://github.com/rust-lang/rust-clippy/pull/4525)
 +* `cargo_common_metadata` now checks for license files [#4518](https://github.com/rust-lang/rust-clippy/pull/4518)
 +* `cognitive_complexity` now includes the measured complexity in the warning message [#4469](https://github.com/rust-lang/rust-clippy/pull/4469)
 +* Fix false positives in `block_in_if_*` lints [#4458](https://github.com/rust-lang/rust-clippy/pull/4458)
 +* Fix false positive in `cast_lossless` [#4473](https://github.com/rust-lang/rust-clippy/pull/4473)
 +* Fix false positive in `clone_on_copy` [#4411](https://github.com/rust-lang/rust-clippy/pull/4411)
 +* Fix false positive in `deref_addrof` [#4487](https://github.com/rust-lang/rust-clippy/pull/4487)
 +* Fix false positive in `too_many_lines` [#4490](https://github.com/rust-lang/rust-clippy/pull/4490)
 +* Fix false positive in `new_ret_no_self` [#4365](https://github.com/rust-lang/rust-clippy/pull/4365)
 +* Fix false positive in `manual_swap` [#4478](https://github.com/rust-lang/rust-clippy/pull/4478)
 +* Fix false positive in `missing_const_for_fn` [#4450](https://github.com/rust-lang/rust-clippy/pull/4450)
 +* Fix false positive in `extra_unused_lifetimes` [#4477](https://github.com/rust-lang/rust-clippy/pull/4477)
 +* Fix false positive in `inherent_to_string` [#4460](https://github.com/rust-lang/rust-clippy/pull/4460)
 +* Fix false positive in `map_entry` [#4495](https://github.com/rust-lang/rust-clippy/pull/4495)
 +* Fix false positive in `unused_unit` [#4445](https://github.com/rust-lang/rust-clippy/pull/4445)
 +* Fix false positive in `redundant_pattern` [#4489](https://github.com/rust-lang/rust-clippy/pull/4489)
 +* Fix false positive in `wrong_self_convention` [#4369](https://github.com/rust-lang/rust-clippy/pull/4369)
 +* Improve various suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4558](https://github.com/rust-lang/rust-clippy/pull/4558)
 +* Improve suggestions for `redundant_pattern_matching` [#4352](https://github.com/rust-lang/rust-clippy/pull/4352)
 +* Improve suggestions for `explicit_write` [#4544](https://github.com/rust-lang/rust-clippy/pull/4544)
 +* Improve suggestion for `or_fun_call` [#4522](https://github.com/rust-lang/rust-clippy/pull/4522)
 +* Improve suggestion for `match_as_ref` [#4446](https://github.com/rust-lang/rust-clippy/pull/4446)
 +* Improve suggestion for `unnecessary_fold_span` [#4382](https://github.com/rust-lang/rust-clippy/pull/4382)
 +* Add suggestions for `unseparated_literal_suffix` [#4401](https://github.com/rust-lang/rust-clippy/pull/4401)
 +* Add suggestions for `char_lit_as_u8` [#4418](https://github.com/rust-lang/rust-clippy/pull/4418)
 +
 +## Rust 1.38
 +
 +Released 2019-09-26
 +
 +[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860)
 +
 +* New Lints:
 +  * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
 +  * [`inherent_to_string`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`inherent_to_string_shadow_display`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`type_repetition_in_bounds`] [#3766](https://github.com/rust-lang/rust-clippy/pull/3766)
 +  * [`try_err`] [#4222](https://github.com/rust-lang/rust-clippy/pull/4222)
 +* Move `{unnecessary,panicking}_unwrap` out of nursery [#4307](https://github.com/rust-lang/rust-clippy/pull/4307)
 +* Extend the `use_self` lint to suggest uses of `Self::Variant` [#4308](https://github.com/rust-lang/rust-clippy/pull/4308)
 +* Improve suggestion for needless return [#4262](https://github.com/rust-lang/rust-clippy/pull/4262)
 +* Add auto-fixable suggestion for `let_unit` [#4337](https://github.com/rust-lang/rust-clippy/pull/4337)
 +* Fix false positive in `pub_enum_variant_names` and `enum_variant_names` [#4345](https://github.com/rust-lang/rust-clippy/pull/4345)
 +* Fix false positive in `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Fix false positive in `string_lit_as_bytes` [#4233](https://github.com/rust-lang/rust-clippy/pull/4233)
 +* Fix false positive in `needless_lifetimes` [#4266](https://github.com/rust-lang/rust-clippy/pull/4266)
 +* Fix false positive in `float_cmp` [#4275](https://github.com/rust-lang/rust-clippy/pull/4275)
 +* Fix false positives in `needless_return` [#4274](https://github.com/rust-lang/rust-clippy/pull/4274)
 +* Fix false negative in `match_same_arms` [#4246](https://github.com/rust-lang/rust-clippy/pull/4246)
 +* Fix incorrect suggestion for `needless_bool` [#4335](https://github.com/rust-lang/rust-clippy/pull/4335)
 +* Improve suggestion for `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Improve suggestion for `single_char_literal` [#4361](https://github.com/rust-lang/rust-clippy/pull/4361)
 +* Improve suggestion for `len_zero` [#4314](https://github.com/rust-lang/rust-clippy/pull/4314)
 +* Fix ICE in `implicit_hasher` [#4268](https://github.com/rust-lang/rust-clippy/pull/4268)
 +* Fix allow bug in `trivially_copy_pass_by_ref` [#4250](https://github.com/rust-lang/rust-clippy/pull/4250)
 +
 +## Rust 1.37
 +
 +Released 2019-08-15
 +
 +[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e)
 +
 +* New Lints:
 +  * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
 +  * [`get_last_with_len`] [#3832](https://github.com/rust-lang/rust-clippy/pull/3832)
 +  * [`integer_division`] [#4195](https://github.com/rust-lang/rust-clippy/pull/4195)
 +* Renamed Lint: `const_static_lifetime` is now called [`redundant_static_lifetimes`].
 +  The lint now covers statics in addition to consts [#4162](https://github.com/rust-lang/rust-clippy/pull/4162)
 +* [`match_same_arms`] now warns for all identical arms, instead of only the first one [#4102](https://github.com/rust-lang/rust-clippy/pull/4102)
 +* [`needless_return`] now works with void functions [#4220](https://github.com/rust-lang/rust-clippy/pull/4220)
 +* Fix false positive in [`redundant_closure`] [#4190](https://github.com/rust-lang/rust-clippy/pull/4190)
 +* Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107)
 +* Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214)
 +* Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136)
 +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164)
 +* Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119)
 +* Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137)
 +* Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071)
 +* Add macro check for [`unreadable_literal`] [#4099](https://github.com/rust-lang/rust-clippy/pull/4099)
 +
 +## Rust 1.36
 +
 +Released 2019-07-04
 +
 +[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7)
 +
 +* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
 +* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
 +* Move `path_buf_push_overwrite` to the nursery [#4013](https://github.com/rust-lang/rust-clippy/pull/4013)
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Allow allowing of [`toplevel_ref_arg`] lint [#4007](https://github.com/rust-lang/rust-clippy/pull/4007)
 +* Fix false negative in [`or_fun_call`] pertaining to nested constructors [#4084](https://github.com/rust-lang/rust-clippy/pull/4084)
 +* Fix false positive in [`or_fun_call`] pertaining to enum variant constructors [#4018](https://github.com/rust-lang/rust-clippy/pull/4018)
 +* Fix false positive in [`useless_let_if_seq`] pertaining to interior mutability [#4035](https://github.com/rust-lang/rust-clippy/pull/4035)
 +* Fix false positive in [`redundant_closure`] pertaining to non-function types [#4008](https://github.com/rust-lang/rust-clippy/pull/4008)
 +* Fix false positive in [`let_and_return`] pertaining to attributes on `let`s [#4024](https://github.com/rust-lang/rust-clippy/pull/4024)
 +* Fix false positive in [`module_name_repetitions`] lint pertaining to attributes [#4006](https://github.com/rust-lang/rust-clippy/pull/4006)
 +* Fix false positive on [`assertions_on_constants`] pertaining to `debug_assert!` [#3989](https://github.com/rust-lang/rust-clippy/pull/3989)
 +* Improve suggestion in [`map_clone`] to suggest `.copied()` where applicable  [#3970](https://github.com/rust-lang/rust-clippy/pull/3970) [#4043](https://github.com/rust-lang/rust-clippy/pull/4043)
 +* Improve suggestion for [`search_is_some`] [#4049](https://github.com/rust-lang/rust-clippy/pull/4049)
 +* Improve suggestion applicability for [`naive_bytecount`] [#3984](https://github.com/rust-lang/rust-clippy/pull/3984)
 +* Improve suggestion applicability for [`while_let_loop`] [#3975](https://github.com/rust-lang/rust-clippy/pull/3975)
 +* Improve diagnostics for [`too_many_arguments`] [#4053](https://github.com/rust-lang/rust-clippy/pull/4053)
 +* Improve diagnostics for [`cast_lossless`] [#4021](https://github.com/rust-lang/rust-clippy/pull/4021)
 +* Deal with macro checks in desugarings better [#4082](https://github.com/rust-lang/rust-clippy/pull/4082)
 +* Add macro check for [`unnecessary_cast`]  [#4026](https://github.com/rust-lang/rust-clippy/pull/4026)
 +* Remove [`approx_constant`]'s documentation's "Known problems" section. [#4027](https://github.com/rust-lang/rust-clippy/pull/4027)
 +* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 +* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 +
 +
 +## Rust 1.35
 +
 +Released 2019-05-20
 +
 +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
 +
 +* New lint: `drop_bounds` to detect `T: Drop` bounds
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
 +* Move [`get_unwrap`] to the restriction category
 +* Improve suggestions for [`iter_cloned_collect`]
 +* Improve suggestions for [`cast_lossless`] to suggest suffixed literals
 +* Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
 +* Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
 +* Fix false positive in [`bool_comparison`] pertaining to non-bool types
 +* Fix false positive in [`redundant_closure`] pertaining to differences in borrows
 +* Fix false positive in `option_map_unwrap_or` on non-copy types
 +* Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
 +* Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
 +* Fix false positive in [`needless_continue`] pertaining to loop labels
 +* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 +* Fix false positive for [`use_self`] in nested functions
 +* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
 +* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 +* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 +* Avoid triggering [`redundant_closure`] in macros
 +* ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
 +
 +## Rust 1.34
 +
 +Released 2019-04-10
 +
 +[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
 +
 +* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
 +* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
 +* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
 +* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
 +  configured using the `too-many-lines-threshold` configuration.
 +* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
 +* Expand `redundant_closure` to also work for methods (not only functions)
 +* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
 +* Fix false positive in `cast_sign_loss`
 +* Fix false positive in `integer_arithmetic`
 +* Fix false positive in `unit_arg`
 +* Fix false positives in `implicit_return`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `cast_lossless`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `needless_bool`
 +* Fix incorrect suggestion for `needless_range_loop`
 +* Fix incorrect suggestion for `use_self`
 +* Fix incorrect suggestion for `while_let_on_iterator`
 +* Clippy is now slightly easier to invoke in non-cargo contexts. See
 +  [#3665][pull3665] for more details.
 +* We now have [improved documentation][adding_lints] on how to add new lints
 +
 +## Rust 1.33
 +
 +Released 2019-02-26
 +
 +[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
 +
 +* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
 +* The `rust-clippy` repository is now part of the `rust-lang` org.
 +* Rename `stutter` to `module_name_repetitions`
 +* Merge `new_without_default_derive` into `new_without_default` lint
 +* Move `large_digit_groups` from `style` group to `pedantic`
 +* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
 +  comparisons against booleans
 +* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
 +* Expand `redundant_clone` to work on struct fields
 +* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
 +* Expand `use_self` to work on tuple structs and also in local macros
 +* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
 +* Fix false positives in `implicit_return`
 +* Fix false positives in `use_self`
 +* Fix false negative in `clone_on_copy`
 +* Fix false positive in `doc_markdown`
 +* Fix false positive in `empty_loop`
 +* Fix false positive in `if_same_then_else`
 +* Fix false positive in `infinite_iter`
 +* Fix false positive in `question_mark`
 +* Fix false positive in `useless_asref`
 +* Fix false positive in `wildcard_dependencies`
 +* Fix false positive in `write_with_newline`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `get_unwrap`
 +
 +## Rust 1.32
 +
 +Released 2019-01-17
 +
 +[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 +
 +* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`,
 +  [`redundant_clone`], [`wildcard_dependencies`],
 +  [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`],
 +  [`cargo_common_metadata`]
 +* Add support for `u128` and `i128` to integer related lints
 +* Add float support to `mistyped_literal_suffixes`
 +* Fix false positives in `use_self`
 +* Fix false positives in `missing_comma`
 +* Fix false positives in `new_ret_no_self`
 +* Fix false positives in `possible_missing_comma`
 +* Fix false positive in `integer_arithmetic` in constant items
 +* Fix false positive in `needless_borrow`
 +* Fix false positive in `out_of_bounds_indexing`
 +* Fix false positive in `new_without_default_derive`
 +* Fix false positive in `string_lit_as_bytes`
 +* Fix false negative in `out_of_bounds_indexing`
 +* Fix false negative in `use_self`. It will now also check existential types
 +* Fix incorrect suggestion for `redundant_closure_call`
 +* Fix various suggestions that contained expanded macros
 +* Fix `bool_comparison` triggering 3 times on on on the same code
 +* Expand `trivially_copy_pass_by_ref` to work on trait methods
 +* Improve suggestion for `needless_range_loop`
 +* Move `needless_pass_by_value` from `pedantic` group to `style`
 +
 +## Rust 1.31
 +
 +Released 2018-12-06
 +
 +[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
 +
 +* Clippy has been relicensed under a dual MIT / Apache license.
 +  See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
 +  information.
 +* With Rust 1.31, Clippy is no longer available via crates.io. The recommended
 +  installation method is via `rustup component add clippy`.
 +* New lints: [`redundant_pattern_matching`], [`unnecessary_filter_map`],
 +  [`unused_unit`], [`map_flatten`], [`mem_replace_option_with_none`]
 +* Fix ICE in `if_let_redundant_pattern_matching`
 +* Fix ICE in `needless_pass_by_value` when encountering a generic function
 +  argument with a lifetime parameter
 +* Fix ICE in `needless_range_loop`
 +* Fix ICE in `single_char_pattern` when encountering a constant value
 +* Fix false positive in `assign_op_pattern`
 +* Fix false positive in `boxed_local` on trait implementations
 +* Fix false positive in `cmp_owned`
 +* Fix false positive in `collapsible_if` when conditionals have comments
 +* Fix false positive in `double_parens`
 +* Fix false positive in `excessive_precision`
 +* Fix false positive in `explicit_counter_loop`
 +* Fix false positive in `fn_to_numeric_cast_with_truncation`
 +* Fix false positive in `map_clone`
 +* Fix false positive in `new_ret_no_self`
 +* Fix false positive in `new_without_default` when `new` is unsafe
 +* Fix false positive in `type_complexity` when using extern types
 +* Fix false positive in `useless_format`
 +* Fix false positive in `wrong_self_convention`
 +* Fix incorrect suggestion for `excessive_precision`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `get_unwrap`
 +* Fix incorrect suggestion for `useless_format`
 +* `fn_to_numeric_cast_with_truncation` lint can be disabled again
 +* Improve suggestions for `manual_memcpy`
 +* Improve help message for `needless_lifetimes`
 +
 +## Rust 1.30
 +
 +Released 2018-10-25
 +
 +[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad)
 +
 +* Deprecate `assign_ops` lint
 +* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
 +  [`needless_collect`], [`copy_iterator`]
 +* `cargo clippy -V` now includes the Clippy commit hash of the Rust
 +  Clippy component
 +* Fix ICE in `implicit_hasher`
 +* Fix ICE when encountering `println!("{}" a);`
 +* Fix ICE when encountering a macro call in match statements
 +* Fix false positive in `default_trait_access`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `similar_names`
 +* Fix false positive in `redundant_field_name`
 +* Fix false positive in `expect_fun_call`
 +* Fix false negative in `identity_conversion`
 +* Fix false negative in `explicit_counter_loop`
 +* Fix `range_plus_one` suggestion and false negative
 +* `print_with_newline` / `write_with_newline`: don't warn about string with several `\n`s in them
 +* Fix `useless_attribute` to also whitelist `unused_extern_crates`
 +* Fix incorrect suggestion for `single_char_pattern`
 +* Improve suggestion for `identity_conversion` lint
 +* Move `explicit_iter_loop` and `explicit_into_iter_loop` from `style` group to `pedantic`
 +* Move `range_plus_one` and `range_minus_one` from `nursery` group to `complexity`
 +* Move `shadow_unrelated` from `restriction` group to `pedantic`
 +* Move `indexing_slicing` from `pedantic` group to `restriction`
 +
 +## Rust 1.29
 +
 +Released 2018-09-13
 +
 +[v0.0.212...14207503](https://github.com/rust-lang/rust-clippy/compare/v0.0.212...14207503)
 +
 +* :tada: :tada: **Rust 1.29 is the first stable Rust that includes a bundled Clippy** :tada:
 +  :tada:
 +  You can now run `rustup component add clippy-preview` and then `cargo
 +  clippy` to run Clippy. This should put an end to the continuous nightly
 +  upgrades for Clippy users.
 +* Clippy now follows the Rust versioning scheme instead of its own
 +* Fix ICE when encountering a `while let (..) = x.iter()` construct
 +* Fix false positives in `use_self`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `useless_attribute` lint
 +* Fix false positive in `print_literal`
 +* Fix `use_self` regressions
 +* Improve lint message for `neg_cmp_op_on_partial_ord`
 +* Improve suggestion highlight for `single_char_pattern`
 +* Improve suggestions for various print/write macro lints
 +* Improve website header
 +
 +## 0.0.212 (2018-07-10)
 +* Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 +
 +## 0.0.211
 +* Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
 +
 +## 0.0.210
 +* Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
 +
 +## 0.0.209
 +* Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
 +
 +## 0.0.208
 +* Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
 +
 +## 0.0.207
 +* Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
 +
 +## 0.0.206
 +* Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
 +
 +## 0.0.205
 +* Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
 +* Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
 +
 +## 0.0.204
 +* Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
 +
 +## 0.0.203
 +* Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
 +* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 +
 +## 0.0.202
 +* Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
 +
 +## 0.0.201
 +* Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
 +
 +## 0.0.200
 +* Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
 +
 +## 0.0.199
 +* Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
 +
 +## 0.0.198
 +* Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
 +
 +## 0.0.197
 +* Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
 +
 +## 0.0.196
 +* Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
 +
 +## 0.0.195
 +* Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
 +
 +## 0.0.194
 +* Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
 +* New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
 +
 +## 0.0.193
 +* Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
 +
 +## 0.0.192
 +* Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
 +* New lint: [`print_literal`]
 +
 +## 0.0.191
 +* Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
 +* Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
 +
 +## 0.0.190
 +* Fix a bunch of intermittent cargo bugs
 +
 +## 0.0.189
 +* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
 +
 +## 0.0.188
 +* Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
 +* New lint: [`while_immutable_condition`]
 +
 +## 0.0.187
 +* Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
 +* New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
 +
 +## 0.0.186
 +* Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
 +* Various false positive fixes
 +
 +## 0.0.185
 +* Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
 +* New lint: [`question_mark`]
 +
 +## 0.0.184
 +* Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
 +* New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
 +
 +## 0.0.183
 +* Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
 +* New lint: [`misaligned_transmute`]
 +
 +## 0.0.182
 +* Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
 +* New lint: [`decimal_literal_representation`]
 +
 +## 0.0.181
 +* Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
 +* New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
 +* Removed `unit_expr`
 +* Various false positive fixes for [`needless_pass_by_value`]
 +
 +## 0.0.180
 +* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
 +
 +## 0.0.179
 +* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
 +
 +## 0.0.178
 +* Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
 +
 +## 0.0.177
 +* Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
 +* New lint: [`match_as_ref`]
 +
 +## 0.0.176
 +* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
 +
 +## 0.0.175
 +* Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
 +
 +## 0.0.174
 +* Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
 +
 +## 0.0.173
 +* Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
 +
 +## 0.0.172
 +* Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
 +
 +## 0.0.171
 +* Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
 +
 +## 0.0.170
 +* Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
 +
 +## 0.0.169
 +* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
 +* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
 +
 +## 0.0.168
 +* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
 +
 +## 0.0.167
 +* Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
 +* New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
 +
 +## 0.0.166
 +* Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
 +* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], `invalid_ref`, [`option_map_or_none`],
 +  [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
 +  [`transmute_int_to_float`]
 +
 +## 0.0.165
 +* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
 +* New lint: [`mut_range_bound`]
 +
 +## 0.0.164
 +* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
 +* New lint: [`int_plus_one`]
 +
 +## 0.0.163
 +* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
 +
 +## 0.0.162
 +* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
 +* New lint: [`chars_last_cmp`]
 +* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
 +
 +## 0.0.161
 +* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
 +
 +## 0.0.160
 +* Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
 +
 +## 0.0.159
 +* Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
 +* New lint: [`clone_on_ref_ptr`]
 +
 +## 0.0.158
 +* New lint: [`manual_memcpy`]
 +* [`cast_lossless`] no longer has redundant parentheses in its suggestions
 +* Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
 +
 +## 0.0.157 - 2017-09-04
 +* Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
 +* New lint: `unit_expr`
 +
 +## 0.0.156 - 2017-09-03
 +* Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
 +
 +## 0.0.155
 +* Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
 +* New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
 +
 +## 0.0.154
 +* Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
 +* Fix [`use_self`] triggering inside derives
 +* Add support for linting an entire workspace with `cargo clippy --all`
 +* New lint: [`naive_bytecount`]
 +
 +## 0.0.153
 +* Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
 +* New lint: [`use_self`]
 +
 +## 0.0.152
 +* Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
 +
 +## 0.0.151
 +* Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
 +
 +## 0.0.150
 +* Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
 +
 +## 0.0.148
 +* Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
 +* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
 +
 +## 0.0.147
 +* Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
 +
 +## 0.0.146
 +* Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
 +* Fixes false positives in `inline_always`
 +* Fixes false negatives in `panic_params`
 +
 +## 0.0.145
 +* Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
 +
 +## 0.0.144
 +* Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
 +
 +## 0.0.143
 +* Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
 +* Fix `cargo clippy` crashing on `dylib` projects
 +* Fix false positives around `nested_while_let` and `never_loop`
 +
 +## 0.0.142
 +* Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
 +
 +## 0.0.141
 +* Rewrite of the `doc_markdown` lint.
 +* Deprecated [`range_step_by_zero`]
 +* New lint: [`iterator_step_by_zero`]
 +* New lint: [`needless_borrowed_reference`]
 +* Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
 +
 +## 0.0.140 - 2017-06-16
 +* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
 +
 +## 0.0.139 — 2017-06-10
 +* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
 +* Fix bugs with for loop desugaring
 +* Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
 +
 +## 0.0.138 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
 +
 +## 0.0.137 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
 +
 +## 0.0.136 — 2017—05—26
 +* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
 +
 +## 0.0.135 — 2017—05—24
 +* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
 +
 +## 0.0.134 — 2017—05—19
 +* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
 +
 +## 0.0.133 — 2017—05—14
 +* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
 +
 +## 0.0.132 — 2017—05—05
 +* Fix various bugs and some ices
 +
 +## 0.0.131 — 2017—05—04
 +* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
 +
 +## 0.0.130 — 2017—05—03
 +* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
 +
 +## 0.0.129 — 2017-05-01
 +* Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
 +
 +## 0.0.128 — 2017-04-28
 +* Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
 +
 +## 0.0.127 — 2017-04-27
 +* Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
 +* New lint: [`needless_continue`]
 +
 +## 0.0.126 — 2017-04-24
 +* Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
 +
 +## 0.0.125 — 2017-04-19
 +* Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
 +
 +## 0.0.124 — 2017-04-16
 +* Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
 +
 +## 0.0.123 — 2017-04-07
 +* Fix various false positives
 +
 +## 0.0.122 — 2017-04-07
 +* Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
 +* New lint: [`op_ref`]
 +
 +## 0.0.121 — 2017-03-21
 +* Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
 +
 +## 0.0.120 — 2017-03-17
 +* Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
 +
 +## 0.0.119 — 2017-03-13
 +* Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
 +
 +## 0.0.118 — 2017-03-05
 +* Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
 +
 +## 0.0.117 — 2017-03-01
 +* Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
 +
 +## 0.0.116 — 2017-02-28
 +* Fix `cargo clippy` on 64 bit windows systems
 +
 +## 0.0.115 — 2017-02-27
 +* Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
 +* New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
 +
 +## 0.0.114 — 2017-02-08
 +* Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
 +* Tests are now ui tests (testing the exact output of rustc)
 +
 +## 0.0.113 — 2017-02-04
 +* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
 +* New lint: [`large_enum_variant`]
 +* `explicit_into_iter_loop` provides suggestions
 +
 +## 0.0.112 — 2017-01-27
 +* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
 +
 +## 0.0.111 — 2017-01-21
 +* Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
 +
 +## 0.0.110 — 2017-01-20
 +* Add badges and categories to `Cargo.toml`
 +
 +## 0.0.109 — 2017-01-19
 +* Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
 +
 +## 0.0.108 — 2017-01-12
 +* Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
 +
 +## 0.0.107 — 2017-01-11
 +* Update regex dependency
 +* Fix FP when matching `&&mut` by `&ref`
 +* Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
 +* New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
 +
 +## 0.0.106 — 2017-01-04
 +* Fix FP introduced by rustup in [`wrong_self_convention`]
 +
 +## 0.0.105 — 2017-01-04
 +* Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
 +* New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
 +* Fix suggestion in [`new_without_default`]
 +* FP fix in [`absurd_extreme_comparisons`]
 +
 +## 0.0.104 — 2016-12-15
 +* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
 +
 +## 0.0.103 — 2016-11-25
 +* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
 +
 +## 0.0.102 — 2016-11-24
 +* Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
 +
 +## 0.0.101 — 2016-11-23
 +* Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
 +* New lint: [`string_extend_chars`]
 +
 +## 0.0.100 — 2016-11-20
 +* Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
 +
 +## 0.0.99 — 2016-11-18
 +* Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
 +* New lint: [`get_unwrap`]
 +
 +## 0.0.98 — 2016-11-08
 +* Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
 +
 +## 0.0.97 — 2016-11-03
 +* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
 +  previously added for a short time under the name `clippy` but removed for
 +  compatibility.
 +* `cargo clippy --help` is more helping (and less helpful :smile:)
 +* Rustup to *rustc 1.14.0-nightly (5665bdf3e 2016-11-02)*
 +* New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
 +
 +## 0.0.96 — 2016-10-22
 +* Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
 +* New lint: [`iter_skip_next`]
 +
 +## 0.0.95 — 2016-10-06
 +* Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
 +
 +## 0.0.94 — 2016-10-04
 +* Fixes bustage on Windows due to forbidden directory name
 +
 +## 0.0.93 — 2016-10-03
 +* Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
 +* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
 +  allowed by default.
 +* New lint: [`explicit_into_iter_loop`]
 +
 +## 0.0.92 — 2016-09-30
 +* Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
 +
 +## 0.0.91 — 2016-09-28
 +* Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
 +
 +## 0.0.90 — 2016-09-09
 +* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
 +
 +## 0.0.89 — 2016-09-06
 +* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
 +
 +## 0.0.88 — 2016-09-04
 +* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
 +* The following lints are not new but were only usable through the `clippy`
 +  lint groups: [`filter_next`], `for_loop_over_option`,
 +  `for_loop_over_result` and [`match_overlapping_arm`]. You should now be
 +  able to `#[allow/deny]` them individually and they are available directly
 +  through `cargo clippy`.
 +
 +## 0.0.87 — 2016-08-31
 +* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
 +* New lints: [`builtin_type_shadow`]
 +* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
 +
 +## 0.0.86 — 2016-08-28
 +* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
 +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
 +
 +## 0.0.85 — 2016-08-19
 +* Fix ICE with [`useless_attribute`]
 +* [`useless_attribute`] ignores `unused_imports` on `use` statements
 +
 +## 0.0.84 — 2016-08-18
 +* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
 +
 +## 0.0.83 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
 +* New lints: [`print_with_newline`], [`useless_attribute`]
 +
 +## 0.0.82 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
 +* New lint: [`module_inception`]
 +
 +## 0.0.81 — 2016-08-14
 +* Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
 +* New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
 +* False positive fix in [`too_many_arguments`]
 +* Addition of functionality to [`needless_borrow`]
 +* Suggestions for [`clone_on_copy`]
 +* Bug fix in [`wrong_self_convention`]
 +* Doc improvements
 +
 +## 0.0.80 — 2016-07-31
 +* Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
 +* New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
 +
 +## 0.0.79 — 2016-07-10
 +* Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
 +* Major suggestions refactoring
 +
 +## 0.0.78 — 2016-07-02
 +* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
 +* New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
 +* For compatibility, `cargo clippy` does not defines the `clippy` feature
 +  introduced in 0.0.76 anymore
 +* [`collapsible_if`] now considers `if let`
 +
 +## 0.0.77 — 2016-06-21
 +* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
 +* New lints: `stutter` and [`iter_nth`]
 +
 +## 0.0.76 — 2016-06-10
 +* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
 +* `cargo clippy` now automatically defines the `clippy` feature
 +* New lint: [`not_unsafe_ptr_arg_deref`]
 +
 +## 0.0.75 — 2016-06-08
 +* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
 +
 +## 0.0.74 — 2016-06-07
 +* Fix bug with `cargo-clippy` JSON parsing
 +* Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
 +  “for further information visit *lint-link*” message.
 +
 +## 0.0.73 — 2016-06-05
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.72 — 2016-06-04
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.71 — 2016-05-31
 +* Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
 +* New lint: [`useless_let_if_seq`]
 +
 +## 0.0.70 — 2016-05-28
 +* Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
 +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
 +  `RegexBuilder::new` and byte regexes
 +
 +## 0.0.69 — 2016-05-20
 +* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
 +* [`used_underscore_binding`] has been made `Allow` temporarily
 +
 +## 0.0.68 — 2016-05-17
 +* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
 +* New lint: [`unnecessary_operation`]
 +
 +## 0.0.67 — 2016-05-12
 +* Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
 +
 +## 0.0.66 — 2016-05-11
 +* New `cargo clippy` subcommand
 +* New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
 +
 +## 0.0.65 — 2016-05-08
 +* Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
 +* New lints: [`float_arithmetic`], [`integer_arithmetic`]
 +
 +## 0.0.64 — 2016-04-26
 +* Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
 +* New lints: `temporary_cstring_as_ptr`, [`unsafe_removed_from_name`], and [`mem_forget`]
 +
 +## 0.0.63 — 2016-04-08
 +* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
 +
 +## 0.0.62 — 2016-04-07
 +* Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
 +
 +## 0.0.61 — 2016-04-03
 +* Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
 +* New lint: [`invalid_upcast_comparisons`]
 +
 +## 0.0.60 — 2016-04-01
 +* Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
 +
 +## 0.0.59 — 2016-03-31
 +* Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
 +* New lints: [`logic_bug`], [`nonminimal_bool`]
 +* Fixed: [`match_same_arms`] now ignores arms with guards
 +* Improved: [`useless_vec`] now warns on `for … in vec![…]`
 +
 +## 0.0.58 — 2016-03-27
 +* Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
 +* New lint: [`doc_markdown`]
 +
 +## 0.0.57 — 2016-03-27
 +* Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
 +* Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
 +* New lint: [`crosspointer_transmute`]
 +
 +## 0.0.56 — 2016-03-23
 +* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
 +* New lints: [`many_single_char_names`] and [`similar_names`]
 +
 +## 0.0.55 — 2016-03-21
 +* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
 +
 +## 0.0.54 — 2016-03-16
 +* Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
 +
 +## 0.0.53 — 2016-03-15
 +* Add a [configuration file]
 +
 +## ~~0.0.52~~
 +
 +## 0.0.51 — 2016-03-13
 +* Add `str` to types considered by [`len_zero`]
 +* New lints: [`indexing_slicing`]
 +
 +## 0.0.50 — 2016-03-11
 +* Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
 +
 +## 0.0.49 — 2016-03-09
 +* Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
 +* New lints: [`overflow_check_conditional`], `unused_label`, [`new_without_default`]
 +
 +## 0.0.48 — 2016-03-07
 +* Fixed: ICE in [`needless_range_loop`] with globals
 +
 +## 0.0.47 — 2016-03-07
 +* Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
 +* New lint: [`redundant_closure_call`]
 +
 +[`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html
 +[`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
 +[configuration file]: ./rust-clippy#configuration
 +[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/adding_lints.md
 +[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
 +
 +<!-- lint disable no-unused-definitions -->
 +<!-- begin autogenerated links to lint list -->
 +[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 +[`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 +[`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
 +[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
++[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
 +[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 +[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 +[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
 +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 +[`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut
 +[`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
 +[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 +[`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states
 +[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 +[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
 +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
 +[`await_holding_invalid_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type
 +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 +[`await_holding_refcell_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_refcell_ref
 +[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 +[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 +[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
 +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 +[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
 +[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
 +[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 +[`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 +[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 +[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if
 +[`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
 +[`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref
 +[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 +[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 +[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
 +[`box_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_default
 +[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
 +[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 +[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 +[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 +[`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
 +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 +[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
 +[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
 +[`cast_abs_to_unsigned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned
 +[`cast_enum_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_constructor
 +[`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation
 +[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`cast_nan_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_nan_to_int
 +[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 +[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 +[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 +[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
 +[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 +[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 +[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
 +[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
 +[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 +[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 +[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
 +[`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions
 +[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
 +[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
 +[`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
 +[`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied
 +[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 +[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 +[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
 +[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 +[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 +[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 +[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace
 +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 +[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 +[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
 +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 +[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 +[`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity
 +[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 +[`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_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
 +[`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation
 +[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 +[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 +[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 +[`deref_by_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_by_slicing
 +[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
 +[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 +[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 +[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
 +[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
 +[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 +[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
 +[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
 +[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 +[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 +[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 +[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 +[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
 +[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 +[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 +[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 +[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
 +[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
 +[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 +[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 +[`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_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
 +[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
 +[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
 +[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
 +[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
 +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 +[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 +[`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
 +[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 +[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
 +[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
 +[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
 +[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
 +[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
 +[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used
 +[`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
 +[`explicit_auto_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_auto_deref
 +[`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop
 +[`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods
 +[`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
 +[`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
 +[`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write
 +[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 +[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
 +[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
 +[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 +[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 +[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 +[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 +[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 +[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
 +[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
 +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
 +[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
 +[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
 +[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
 +[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 +[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 +[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
 +[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 +[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
 +[`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option
 +[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result
 +[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 +[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 +[`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
 +[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
 +[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 +[`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
 +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 +[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 +[`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
 +[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 +[`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first
 +[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 +[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 +[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
 +[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 +[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 +[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 +[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 +[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 +[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
 +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
 +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 +[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 +[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
 +[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
 +[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
 +[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
 +[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
 +[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
 +[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
 +[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 +[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 +[`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields
 +[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
 +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
 +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
 +[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
 +[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked
 +[`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
 +[`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
 +[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 +[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 +[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 +[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
 +[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
 +[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 +[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
 +[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 +[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
 +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
 +[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
 +[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
 +[`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file
 +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 +[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
 +[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 +[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 +[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
 +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
 +[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
 +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
 +[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 +[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 +[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 +[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
 +[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
 +[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
 +[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
 +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
 +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 +[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
 +[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
 +[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
 +[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
 +[`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_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
 +[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
 +[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
 +[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 +[`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
 +[`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
 +[`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
 +[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 +[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 +[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 +[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 +[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 +[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
 +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
 +[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
 +[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
 +[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
 +[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
 +[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
 +[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
 +[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 +[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
 +[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 +[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 +[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 +[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 +[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 +[`mismatching_type_param_order`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatching_type_param_order
 +[`misnamed_getters`]: https://rust-lang.github.io/rust-clippy/master/index.html#misnamed_getters
 +[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 +[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 +[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 +[`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
 +[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
 +[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 +[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
 +[`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
 +[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 +[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 +[`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression
 +[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
 +[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
 +[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 +[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
 +[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
 +[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 +[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 +[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
 +[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
 +[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
 +[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
 +[`mut_mutex_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mutex_lock
 +[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
 +[`mutable_key_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
 +[`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
 +[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 +[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 +[`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_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
 +[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 +[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 +[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
 +[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match
 +[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
 +[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
 +[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 +[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 +[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 +[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 +[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 +[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
 +[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
 +[`negative_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#negative_feature_names
 +[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 +[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 +[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 +[`new_without_default_derive`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default_derive
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
 +[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`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
 +[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 +[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`obfuscated_if_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#obfuscated_if_else
 +[`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes
 +[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 +[`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some
 +[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 +[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
 +[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used
 +[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
 +[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 +[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 +[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
 +[`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or
 +[`option_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else
 +[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
 +[`option_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_used
 +[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 +[`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
 +[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 +[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 +[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr
 +[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 +[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
 +[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 +[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 +[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 +[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 +[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 +[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 +[`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
 +[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
 +[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
 +[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 +[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 +[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 +[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 +[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 +[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 +[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
 +[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
 +[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 +[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 +[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 +[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
 +[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
 +[`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init
 +[`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 +[`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
 +[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
 +[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 +[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
 +[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 +[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
 +[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 +[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 +[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 +[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 +[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 +[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 +[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 +[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 +[`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
 +[`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
 +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 +[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
 +[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
 +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 +[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 +[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
 +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
 +[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
 +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 +[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
 +[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 +[`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current
 +[`seek_to_start_instead_of_rewind`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_to_start_instead_of_rewind
 +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 +[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 +[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
++[`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block
++[`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
 +[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 +[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 +[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 +[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 +[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
 +[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 +[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 +[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 +[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
 +[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 +[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
 +[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 +[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 +[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 +[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 +[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 +[`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc
 +[`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core
 +[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 +[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 +[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
 +[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 +[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
 +[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 +[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
 +[`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
 +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 +[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 +[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
 +[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
 +[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 +[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 +[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
 +[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
 +[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
 +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 +[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 +[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 +[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 +[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
 +[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 +[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 +[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 +[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
 +[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
 +[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 +[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 +[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 +[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 +[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 +[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
 +[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 +[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 +[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 +[`transmute_undefined_repr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_undefined_repr
 +[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 +[`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 +[`trim_split_whitespace`]: https://rust-lang.github.io/rust-clippy/master/index.html#trim_split_whitespace
 +[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
 +[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
 +[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 +[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 +[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
 +[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
 +[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
 +[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 +[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 +[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
 +[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
 +[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
 +[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
 +[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
 +[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
 +[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 +[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
 +[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join
 +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 +[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 +[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 +[`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
 +[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
 +[`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
 +[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
 +[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
 +[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
 +[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
 +[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
 +[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
 +[`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize
 +[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
 +[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization
 +[`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
 +[`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 +[`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 +[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
 +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 +[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 +[`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
 +[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 +[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
 +[`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 +[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 +[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 +[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
 +[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 +[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
 +[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
 +[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
 +[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
 +[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 +[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
 +[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 +[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 +[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
 +[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 +[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 +[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
 +[`vec_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
 +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 +[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 +[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 +[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 +[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 +[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 +[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
 +[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
 +[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
 +[`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports
 +[`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns
 +[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
 +[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
 +[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string
 +[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
 +[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
 +[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
 +[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 +[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 +[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
 +[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
 +[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index fe425a2fb991fdb1377b985eb83d007156ad58dc,0000000000000000000000000000000000000000..f8cb4b7219c47467e6e41412b57f17733c02a46b
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,67 @@@
- version = "0.1.67"
 +[package]
 +name = "clippy"
- rustc_tools_util = "0.2.1"
++version = "0.1.68"
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +categories = ["development-tools", "development-tools::cargo-plugins"]
 +build = "build.rs"
 +edition = "2021"
 +publish = false
 +
 +[[bin]]
 +name = "cargo-clippy"
 +test = false
 +path = "src/main.rs"
 +
 +[[bin]]
 +name = "clippy-driver"
 +path = "src/driver.rs"
 +
 +[dependencies]
 +clippy_lints = { path = "clippy_lints" }
 +semver = "1.0"
- rustc_tools_util = "0.2.1"
++rustc_tools_util = "0.3.0"
 +tempfile = { version = "3.2", optional = true }
 +termize = "0.1"
 +
 +[dev-dependencies]
 +compiletest_rs = { version = "0.9", features = ["tmp"] }
 +tester = "0.9"
 +regex = "1.5"
 +toml = "0.5"
 +walkdir = "2.3"
 +# This is used by the `collect-metadata` alias.
 +filetime = "0.2"
 +
 +# 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"
 +
 +# UI test dependencies
 +clippy_utils = { path = "clippy_utils" }
 +derive-new = "0.5"
 +if_chain = "1.0"
 +itertools = "0.10.1"
 +quote = "1.0"
 +serde = { version = "1.0.125", features = ["derive"] }
 +syn = { version = "1.0", features = ["full"] }
 +futures = "0.3"
 +parking_lot = "0.12"
 +tokio = { version = "1", features = ["io-util"] }
 +rustc-semver = "1.1"
 +
 +[build-dependencies]
++rustc_tools_util = "0.3.0"
 +
 +[features]
 +deny-warnings = ["clippy_lints/deny-warnings"]
 +integration = ["tempfile"]
 +internal = ["clippy_lints/internal", "tempfile"]
 +
 +[package.metadata.rust-analyzer]
 +# This package uses #[feature(rustc_private)]
 +rustc_private = true
index 6248d588a890b9dc13038eaa051ca56cd46d18b6,0000000000000000000000000000000000000000..23867df8efe1dc0ce542f3e299df8326fe1ad56d
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
- [![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
 +# Clippy
 +
++[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
 +[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 +
 +A collection of lints to catch common mistakes and improve your
 +[Rust](https://github.com/rust-lang/rust) code.
 +
 +[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 +
 +Lints are divided into categories, each with a default [lint
 +level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
 +much Clippy is supposed to ~~annoy~~ help you by changing the lint level by
 +category.
 +
 +| Category              | Description                                                                         | Default level |
 +| --------------------- | ----------------------------------------------------------------------------------- | ------------- |
 +| `clippy::all`         | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** |
 +| `clippy::correctness` | code that is outright wrong or useless                                              | **deny**      |
 +| `clippy::suspicious`  | code that is most likely wrong or useless                                           | **warn**      |
 +| `clippy::complexity`  | code that does something simple but in a complex way                                | **warn**      |
 +| `clippy::perf`        | code that can be written to run faster                                              | **warn**      |
 +| `clippy::style`       | code that should be written in a more idiomatic way                                 | **warn**      |
 +| `clippy::pedantic`    | lints which are rather strict or might have false positives                         | allow         |
 +| `clippy::nursery`     | new lints that are still under development                                          | allow         |
 +| `clippy::cargo`       | lints for the cargo manifest                                                        | allow         |                                   | allow         |
 +
 +More to come, please [file an
 +issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
 +
 +The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also
 +contains "restriction lints", which are for things which are usually not
 +considered "bad", but may be useful to turn on in specific cases. These should
 +be used very selectively, if at all.
index b5484bec3c8b8dca5dc0a00930d846e60533d4a7,0000000000000000000000000000000000000000..b79d09b0dd2d2776e98a4ae73de9c2884e722677
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,7 @@@
-     // forward git repo hashes we build at
-     println!(
-         "cargo:rustc-env=GIT_HASH={}",
-         rustc_tools_util::get_commit_hash().unwrap_or_default()
-     );
-     println!(
-         "cargo:rustc-env=COMMIT_DATE={}",
-         rustc_tools_util::get_commit_date().unwrap_or_default()
-     );
-     println!(
-         "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-         rustc_tools_util::get_channel()
-     );
 +fn main() {
 +    // Forward the profile to the main compilation
 +    println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
 +    // Don't rebuild even if nothing changed
 +    println!("cargo:rerun-if-changed=build.rs");
++    rustc_tools_util::setup_version_info!();
 +}
index aedff24c12c6078b7aec3236f261837008df36e3,0000000000000000000000000000000000000000..a9f69b1ba6300907b1ec7c4770a53ab98f9eceba
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,39 @@@
- version = "0.1.67"
 +[package]
 +name = "clippy_lints"
++version = "0.1.68"
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +edition = "2021"
 +
 +[dependencies]
 +cargo_metadata = "0.14"
 +clippy_utils = { path = "../clippy_utils" }
 +declare_clippy_lint = { path = "../declare_clippy_lint" }
 +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"
 +serde = { version = "1.0", features = ["derive"] }
 +serde_json = { version = "1.0", optional = true }
 +tempfile = { version = "3.2", optional = true }
 +toml = "0.5"
 +unicode-normalization = "0.1"
 +unicode-script = { version = "0.5", default-features = false }
 +semver = "1.0"
 +rustc-semver = "1.1"
 +# NOTE: cargo requires serde feat in its url dep
 +# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
 +url = { version = "2.2", features = ["serde"] }
 +
 +[features]
 +deny-warnings = ["clippy_utils/deny-warnings"]
 +# build clippy with internal lints enabled, off by default
 +internal = ["clippy_utils/internal", "serde_json", "tempfile"]
 +
 +[package.metadata.rust-analyzer]
 +# This crate uses #[feature(rustc_private)]
 +rustc_private = true
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..42e14b5cd945fc4647cb9fec2a789c303ddcccff
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,114 @@@
++use clippy_utils::diagnostics::span_lint_and_then;
++use clippy_utils::msrvs::{self, Msrv};
++use clippy_utils::source::{trim_span, walk_span_to_context};
++use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
++use rustc_errors::Applicability;
++use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
++use rustc_middle::lint::in_external_macro;
++use rustc_session::{declare_tool_lint, impl_lint_pass};
++use rustc_span::Span;
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z'
++    /// or digits from '0' to '9', but don't because they're a half open range.
++    ///
++    /// ### Why is this bad?
++    /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
++    ///
++    /// ### Example
++    /// ```rust
++    /// let _ = 'a'..'z';
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// let _ = 'a'..='z';
++    /// ```
++    #[clippy::version = "1.63.0"]
++    pub ALMOST_COMPLETE_RANGE,
++    suspicious,
++    "almost complete range"
++}
++impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]);
++
++pub struct AlmostCompleteRange {
++    msrv: Msrv,
++}
++impl AlmostCompleteRange {
++    pub fn new(msrv: Msrv) -> Self {
++        Self { msrv }
++    }
++}
++impl EarlyLintPass for AlmostCompleteRange {
++    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
++        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
++            let ctxt = e.span.ctxt();
++            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
++                && let Some(end) = walk_span_to_context(end.span, ctxt)
++                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
++            {
++                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
++            } else {
++                None
++            };
++            check_range(cx, e.span, start, end, sugg);
++        }
++    }
++
++    fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
++        if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
++            && matches!(kind.node, RangeEnd::Excluded)
++        {
++            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
++                "..="
++            } else {
++                "..."
++            };
++            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
++        }
++    }
++
++    extract_msrv_attr!(EarlyContext);
++}
++
++fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
++    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
++        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
++        && matches!(
++            (
++                LitKind::from_token_lit(start_token_lit),
++                LitKind::from_token_lit(end_token_lit),
++            ),
++            (
++                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
++                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
++            )
++            | (
++                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
++                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
++            )
++            | (
++                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
++                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
++            )
++        )
++        && !in_external_macro(cx.sess(), span)
++    {
++        span_lint_and_then(
++            cx,
++            ALMOST_COMPLETE_RANGE,
++            span,
++            "almost complete ascii range",
++            |diag| {
++                if let Some((span, sugg)) = sugg {
++                    diag.span_suggestion(
++                        span,
++                        "use an inclusive range",
++                        sugg,
++                        Applicability::MaybeIncorrect,
++                    );
++                }
++            }
++        );
++    }
++}
index 36daceabe0bea61a034aeac4dd894cbcff834eb0,0000000000000000000000000000000000000000..91900542af8330e52d72655efb34be044bbfbbf5
mode 100644,000000..100644
--- /dev/null
@@@ -1,129 -1,0 +1,129 @@@
-     #[clippy::version = "1.65.0"]
 +use clippy_utils::{
 +    diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path,
 +    path_def_id, paths, ty::expr_sig,
 +};
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    intravisit::{walk_ty, Visitor},
 +    Block, Expr, ExprKind, Local, Node, QPath, TyKind,
 +};
 +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;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// checks for `Box::new(T::default())`, which is better written as
 +    /// `Box::<T>::default()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// First, it's more complex, involving two calls instead of one.
 +    /// Second, `Box::default()` can be faster
 +    /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: Box<String> = Box::new(Default::default());
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x: Box<String> = Box::default();
 +    /// ```
++    #[clippy::version = "1.66.0"]
 +    pub BOX_DEFAULT,
 +    perf,
 +    "Using Box::new(T::default()) instead of Box::default()"
 +}
 +
 +declare_lint_pass!(BoxDefault => [BOX_DEFAULT]);
 +
 +impl LateLintPass<'_> for BoxDefault {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if let ExprKind::Call(box_new, [arg]) = expr.kind
 +            && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
 +            && let ExprKind::Call(arg_path, ..) = arg.kind
 +            && !in_external_macro(cx.sess(), expr.span)
 +            && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg))
 +            && seg.ident.name == sym::new
 +            && 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,
 +                expr.span,
 +                "`Box::new(_)` of default value",
 +                "try",
 +                if is_plain_default(arg_path) || given_type(cx, expr) {
 +                    "Box::default()".into()
 +                } else {
 +                    format!("Box::<{arg_ty}>::default()")
 +                },
 +                Applicability::MachineApplicable
 +            );
 +        }
 +    }
 +}
 +
 +fn is_plain_default(arg_path: &Expr<'_>) -> bool {
 +    // we need to match the actual path so we don't match e.g. "u8::default"
 +    if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind {
 +        // avoid generic parameters
 +        match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none())
 +    } else {
 +        false
 +    }
 +}
 +
 +fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    macro_backtrace(expr.span)
 +        .next()
 +        .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id))
 +}
 +
 +#[derive(Default)]
 +struct InferVisitor(bool);
 +
 +impl<'tcx> Visitor<'tcx> for InferVisitor {
 +    fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) {
 +        self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
 +        if !self.0 {
 +            walk_ty(self, t);
 +        }
 +    }
 +}
 +
 +fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    match get_parent_node(cx.tcx, expr.hir_id) {
 +        Some(Node::Local(Local { ty: Some(ty), .. })) => {
 +            let mut v = InferVisitor::default();
 +            v.visit_ty(ty);
 +            !v.0
 +        },
 +        Some(
 +            Node::Expr(Expr {
 +                kind: ExprKind::Call(path, args),
 +                ..
 +            }) | Node::Block(Block {
 +                expr:
 +                    Some(Expr {
 +                        kind: ExprKind::Call(path, args),
 +                        ..
 +                    }),
 +                ..
 +            }),
 +        ) => {
 +            if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
 +                let Some(sig) = expr_sig(cx, path) &&
 +                let Some(input) = sig.input(index)
 +            {
 +                input.no_bound_vars().is_some()
 +            } else {
 +                false
 +            }
 +        },
 +        _ => false,
 +    }
 +}
index c6d505c4a181fc2e3b52c2be3b1d713f7123eec2,0000000000000000000000000000000000000000..161e3a698e9ea6133ba0d6a86e2ad70983d7dbf8
mode 100644,000000..100644
--- /dev/null
@@@ -1,742 -1,0 +1,742 @@@
-     #[clippy::version = "1.64.0"]
 +mod as_ptr_cast_mut;
 +mod as_underscore;
 +mod borrow_as_ptr;
 +mod cast_abs_to_unsigned;
 +mod cast_enum_constructor;
 +mod cast_lossless;
 +mod cast_nan_to_int;
 +mod cast_possible_truncation;
 +mod cast_possible_wrap;
 +mod cast_precision_loss;
 +mod cast_ptr_alignment;
 +mod cast_ref_to_mut;
 +mod cast_sign_loss;
 +mod cast_slice_different_sizes;
 +mod cast_slice_from_raw_parts;
 +mod char_lit_as_u8;
 +mod fn_to_numeric_cast;
 +mod fn_to_numeric_cast_any;
 +mod fn_to_numeric_cast_with_truncation;
 +mod ptr_as_ptr;
 +mod unnecessary_cast;
 +mod utils;
 +
 +use clippy_utils::is_hir_ty_cfg_dependant;
 +use clippy_utils::msrvs::{self, Msrv};
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from any numerical to a float type where
 +    /// the receiving type cannot store all values from the original type without
 +    /// rounding errors. This possible rounding is to be expected, so this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// Basically, this warns on casting any integer with 32 or more bits to `f32`
 +    /// or any 64-bit integer to `f64`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not bad at all. But in some applications it can be
 +    /// helpful to know where precision loss can take place. This lint can help find
 +    /// those places in the code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = u64::MAX;
 +    /// x as f64;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_PRECISION_LOSS,
 +    pedantic,
 +    "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from a signed to an unsigned numerical
 +    /// type. In this case, negative values wrap around to large positive values,
 +    /// which can be quite surprising in practice. However, as the cast works as
 +    /// defined, this lint is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// Possibly surprising results. You can activate this lint
 +    /// as a one-time check to see where numerical wrapping can arise.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let y: i8 = -1;
 +    /// y as u128; // will return 18446744073709551615
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_SIGN_LOSS,
 +    pedantic,
 +    "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// truncate large values. This is expected behavior, so the cast is `Allow` by
 +    /// default.
 +    ///
 +    /// ### Why is this bad?
 +    /// In some problem domains, it is good practice to avoid
 +    /// truncation. This lint can be activated to help assess where additional
 +    /// checks could be beneficial.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u8(x: u64) -> u8 {
 +    ///     x as u8
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_POSSIBLE_TRUNCATION,
 +    pedantic,
 +    "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an unsigned type to a signed type of
 +    /// the same size. Performing such a cast is a 'no-op' for the compiler,
 +    /// i.e., nothing is changed at the bit level, and the binary representation of
 +    /// the value is reinterpreted. This can cause wrapping if the value is too big
 +    /// for the target signed type. However, the cast works as defined, so this lint
 +    /// is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// While such a cast is not bad in itself, the results can
 +    /// be surprising when this is not the intended behavior, as demonstrated by the
 +    /// example below.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// u32::MAX as i32; // will yield a value of `-1`
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_POSSIBLE_WRAP,
 +    pedantic,
 +    "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// be replaced by safe conversion functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// Rust's `as` keyword will perform many kinds of
 +    /// conversions, including silently lossy conversions. Conversion functions such
 +    /// as `i32::from` will only perform lossless conversions. Using the conversion
 +    /// functions prevents conversions from turning into silent lossy conversions if
 +    /// the types of the input expressions ever change, and make it easier for
 +    /// people reading the code to know that the conversion is lossless.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     x as u64
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `::from` would look like this:
 +    ///
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     u64::from(x)
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_LOSSLESS,
 +    pedantic,
 +    "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts to the same type, casts of int literals to integer types
 +    /// and casts of float literals to float types.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's just unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = 2i32 as i32;
 +    /// let _ = 0.5 as f32;
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// let _ = 2_i32;
 +    /// let _ = 0.5_f32;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNNECESSARY_CAST,
 +    complexity,
 +    "cast to the same type, e.g., `x as i32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts, using `as` or `pointer::cast`,
 +    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
 +    ///
 +    /// ### Why is this bad?
 +    /// Dereferencing the resulting pointer may be undefined
 +    /// behavior.
 +    ///
 +    /// ### Known problems
 +    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
 +    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
 +    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (&1u8 as *const u8) as *const u16;
 +    /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
 +    ///
 +    /// (&1u8 as *const u8).cast::<u16>();
 +    /// (&mut 1u8 as *mut u8).cast::<u16>();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_PTR_ALIGNMENT,
 +    pedantic,
 +    "cast from a pointer to a more-strictly-aligned pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of function pointers to something other than usize
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to anything other than usize/isize is not portable across
 +    /// architectures, because you end up losing bits if the target type is too small or end up with a
 +    /// bunch of extra bits that waste space and add more instructions to the final binary than
 +    /// strictly necessary for the problem
 +    ///
 +    /// Casting to isize also doesn't make sense since there are no signed addresses.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn fun() -> i32 { 1 }
 +    /// let _ = fun as i64;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # fn fun() -> i32 { 1 }
 +    /// let _ = fun as usize;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FN_TO_NUMERIC_CAST,
 +    style,
 +    "casting a function pointer to a numeric type other than usize"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to a numeric type not wide enough to
 +    /// store address.
 +    ///
 +    /// ### Why is this bad?
 +    /// Such a cast discards some bits of the function's address. If this is intended, it would be more
 +    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
 +    /// a comment) to perform the truncation.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn fn1() -> i16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as i32;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// // Cast to usize first, then comment with the reason for the truncation
 +    /// fn fn1() -> i16 {
 +    ///     1
 +    /// };
 +    /// let fn_ptr = fn1 as usize;
 +    /// let fn_ptr_truncated = fn_ptr as i32;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    style,
 +    "casting a function pointer to a numeric type not wide enough to store the address"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to any integer type.
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to an integer can have surprising results and can occur
 +    /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
 +    /// low-level with function pointers then you can opt-out of casting functions to integers in
 +    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
 +    /// pointer casts in your code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // fn1 is cast as `usize`
 +    /// fn fn1() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as usize;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// // maybe you intended to call the function?
 +    /// fn fn2() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn2() as usize;
 +    ///
 +    /// // or
 +    ///
 +    /// // maybe you intended to cast it to a function type?
 +    /// fn fn3() -> u16 {
 +    ///     1
 +    /// }
 +    /// let _ = fn3 as fn() -> u16;
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub FN_TO_NUMERIC_CAST_ANY,
 +    restriction,
 +    "casting a function pointer to any integer type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of `&T` to `&mut T` anywhere in the code.
 +    ///
 +    /// ### Why is this bad?
 +    /// It’s basically guaranteed to be undefined behavior.
 +    /// `UnsafeCell` is the only way to obtain aliasable data that is considered
 +    /// mutable.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// fn x(r: &i32) {
 +    ///     unsafe {
 +    ///         *(r as *const _ as *mut _) += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Instead consider using interior mutability types.
 +    ///
 +    /// ```rust
 +    /// use std::cell::UnsafeCell;
 +    ///
 +    /// fn x(r: &UnsafeCell<i32>) {
 +    ///     unsafe {
 +    ///         *r.get() += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.33.0"]
 +    pub CAST_REF_TO_MUT,
 +    correctness,
 +    "a cast of reference to a mutable pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions where a character literal is cast
 +    /// to `u8` and suggests using a byte literal instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// In general, casting values to smaller types is
 +    /// error-prone and should be avoided where possible. In the particular case of
 +    /// converting a character literal to u8, it is easy to avoid by just using a
 +    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
 +    /// than `'a' as u8`.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// 'x' as u8
 +    /// ```
 +    ///
 +    /// A better version, using the byte literal:
 +    ///
 +    /// ```rust,ignore
 +    /// b'x'
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHAR_LIT_AS_U8,
 +    complexity,
 +    "casting a character literal to `u8` truncates"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `as` casts between raw pointers without changing its mutability,
 +    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
 +    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr as *const i32;
 +    /// let _ = mut_ptr as *mut i32;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr.cast::<i32>();
 +    /// let _ = mut_ptr.cast::<i32>();
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub PTR_AS_PTR,
 +    pedantic,
 +    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an enum type to an integral type which will definitely truncate the
 +    /// value.
 +    ///
 +    /// ### Why is this bad?
 +    /// The resulting integral value will not match the value of the variant it came from.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum E { X = 256 };
 +    /// let _ = E::X as u8;
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub CAST_ENUM_TRUNCATION,
 +    suspicious,
 +    "casts from an enum type to an integral type which will truncate the value"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `as` casts between raw pointers to slices with differently sized elements.
 +    ///
 +    /// ### Why is this bad?
 +    /// The produced raw pointer to a slice does not update its length metadata. The produced
 +    /// pointer will point to a different number of bytes than the original pointer because the
 +    /// length metadata of a raw slice pointer is in elements rather than bytes.
 +    /// Producing a slice reference from the raw pointer will either create a slice with
 +    /// less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
 +    ///
 +    /// ### Example
 +    /// // Missing data
 +    /// ```rust
 +    /// let a = [1_i32, 2, 3, 4];
 +    /// let p = &a as *const [i32] as *const [u8];
 +    /// unsafe {
 +    ///     println!("{:?}", &*p);
 +    /// }
 +    /// ```
 +    /// // Undefined Behavior (note: also potential alignment issues)
 +    /// ```rust
 +    /// let a = [1_u8, 2, 3, 4];
 +    /// let p = &a as *const [u8] as *const [u32];
 +    /// unsafe {
 +    ///     println!("{:?}", &*p);
 +    /// }
 +    /// ```
 +    /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
 +    /// ```rust
 +    /// let a = [1_i32, 2, 3, 4];
 +    /// let old_ptr = &a as *const [i32];
 +    /// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
 +    /// // The length comes from the known length of 4 i32s times the 4 bytes per i32
 +    /// let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
 +    /// unsafe {
 +    ///     println!("{:?}", &*new_ptr);
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub CAST_SLICE_DIFFERENT_SIZES,
 +    correctness,
 +    "casting using `as` between raw pointers to slices of types with different sizes"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an enum tuple constructor to an integer.
 +    ///
 +    /// ### Why is this bad?
 +    /// The cast is easily confused with casting a c-like enum value to an integer.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum E { X(i32) };
 +    /// let _ = E::X as usize;
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub CAST_ENUM_CONSTRUCTOR,
 +    suspicious,
 +    "casts from an enum tuple constructor to an integer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for uses 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.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: i32 = -42;
 +    /// let y: u32 = x.abs() as u32;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x: i32 = -42;
 +    /// let y: u32 = x.unsigned_abs();
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub CAST_ABS_TO_UNSIGNED,
 +    suspicious,
 +    "casting the result of `abs()` to an unsigned integer can panic"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Check for the usage of `as _` conversion using inferred type.
 +    ///
 +    /// ### Why is this bad?
 +    /// The conversion might include lossy conversion and dangerous cast that might go
 +    /// undetected due to the type being inferred.
 +    ///
 +    /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn foo(n: usize) {}
 +    /// let n: u16 = 256;
 +    /// foo(n as _);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn foo(n: usize) {}
 +    /// let n: u16 = 256;
 +    /// foo(n as usize);
 +    /// ```
 +    #[clippy::version = "1.63.0"]
 +    pub AS_UNDERSCORE,
 +    restriction,
 +    "detects `as _` conversion"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the usage of `&expr as *const T` or
 +    /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
 +    /// `ptr::addr_of_mut` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// This would improve readability and avoid creating a reference
 +    /// that points to an uninitialized value or unaligned place.
 +    /// Read the `ptr::addr_of` docs for more information.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let val = 1;
 +    /// let p = &val as *const i32;
 +    ///
 +    /// let mut val_mut = 1;
 +    /// let p_mut = &mut val_mut as *mut i32;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let val = 1;
 +    /// let p = std::ptr::addr_of!(val);
 +    ///
 +    /// let mut val_mut = 1;
 +    /// let p_mut = std::ptr::addr_of_mut!(val_mut);
 +    /// ```
 +    #[clippy::version = "1.60.0"]
 +    pub BORROW_AS_PTR,
 +    pedantic,
 +    "borrowing just to cast to a raw pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for a raw slice being cast to a slice pointer
 +    ///
 +    /// ### Why is this bad?
 +    /// This can result in multiple `&mut` references to the same location when only a pointer is
 +    /// required.
 +    /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
 +    /// the same [safety requirements] to be upheld.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
 +    /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
 +    /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
 +    /// ```
 +    /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
 +    #[clippy::version = "1.65.0"]
 +    pub CAST_SLICE_FROM_RAW_PARTS,
 +    suspicious,
 +    "casting a slice created from a pointer and length to a slice pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
 +    ///
 +    /// ### Why is this bad?
 +    /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
 +    /// mutability is used, making it unlikely that having it as a mutable pointer is correct.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let string = String::with_capacity(1);
 +    /// let ptr = string.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();
 +    /// 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"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for a known NaN float being cast to an integer
 +    ///
 +    /// ### Why is this bad?
 +    /// NaNs are cast into zero, so one could simply use this and make the
 +    /// code more readable. The lint could also hint at a programmer error.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// let _: (0.0_f32 / 0.0) as u64;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// let _: = 0_u64;
 +    /// ```
++    #[clippy::version = "1.66.0"]
 +    pub CAST_NAN_TO_INT,
 +    suspicious,
 +    "casting a known floating-point NaN into an integer"
 +}
 +
 +pub struct Casts {
 +    msrv: Msrv,
 +}
 +
 +impl Casts {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(Casts => [
 +    CAST_PRECISION_LOSS,
 +    CAST_SIGN_LOSS,
 +    CAST_POSSIBLE_TRUNCATION,
 +    CAST_POSSIBLE_WRAP,
 +    CAST_LOSSLESS,
 +    CAST_REF_TO_MUT,
 +    CAST_PTR_ALIGNMENT,
 +    CAST_SLICE_DIFFERENT_SIZES,
 +    UNNECESSARY_CAST,
 +    FN_TO_NUMERIC_CAST_ANY,
 +    FN_TO_NUMERIC_CAST,
 +    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    CHAR_LIT_AS_U8,
 +    PTR_AS_PTR,
 +    CAST_ENUM_TRUNCATION,
 +    CAST_ENUM_CONSTRUCTOR,
 +    CAST_ABS_TO_UNSIGNED,
 +    AS_UNDERSCORE,
 +    BORROW_AS_PTR,
 +    CAST_SLICE_FROM_RAW_PARTS,
 +    AS_PTR_CAST_MUT,
 +    CAST_NAN_TO_INT,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Casts {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if !in_external_macro(cx.sess(), expr.span) {
 +            ptr_as_ptr::check(cx, expr, &self.msrv);
 +        }
 +
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
 +            if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
 +                return;
 +            }
 +            let (cast_from, cast_to) = (
 +                cx.typeck_results().expr_ty(cast_expr),
 +                cx.typeck_results().expr_ty(expr),
 +            );
 +
 +            if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
 +                return;
 +            }
 +            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
 +            as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
 +            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +
 +            if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
 +                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +                if cast_from.is_numeric() {
 +                    cast_possible_wrap::check(cx, expr, cast_from, cast_to);
 +                    cast_precision_loss::check(cx, expr, cast_from, cast_to);
 +                    cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
 +                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
 +                    cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
 +                }
 +                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
 +                cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
 +            }
 +
 +            as_underscore::check(cx, expr, cast_to_hir);
 +
 +            if self.msrv.meets(msrvs::BORROW_AS_PTR) {
 +                borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
 +            }
 +        }
 +
 +        cast_ref_to_mut::check(cx, expr);
 +        cast_ptr_alignment::check(cx, expr);
 +        char_lit_as_u8::check(cx, expr);
 +        ptr_as_ptr::check(cx, expr, &self.msrv);
 +        cast_slice_different_sizes::check(cx, expr, &self.msrv);
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
index e4d76f07d6b482b13fa7d5fbaf9cb8b6ce9923fd,0000000000000000000000000000000000000000..3cd7d1d7e722833645876976a615e1d5a7de123f
mode 100644,000000..100644
--- /dev/null
@@@ -1,630 -1,0 +1,632 @@@
-     crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +pub(crate) static LINTS: &[&crate::LintInfo] = &[
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
 +    #[cfg(feature = "internal")]
 +    crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
++    crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
 +    crate::approx_const::APPROX_CONSTANT_INFO,
 +    crate::as_conversions::AS_CONVERSIONS_INFO,
 +    crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
 +    crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,
 +    crate::assertions_on_constants::ASSERTIONS_ON_CONSTANTS_INFO,
 +    crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO,
 +    crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO,
 +    crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO,
 +    crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
 +    crate::attrs::DEPRECATED_CFG_ATTR_INFO,
 +    crate::attrs::DEPRECATED_SEMVER_INFO,
 +    crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
 +    crate::attrs::INLINE_ALWAYS_INFO,
 +    crate::attrs::MISMATCHED_TARGET_OS_INFO,
 +    crate::attrs::USELESS_ATTRIBUTE_INFO,
 +    crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
 +    crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
 +    crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
 +    crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO,
 +    crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
 +    crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
 +    crate::booleans::NONMINIMAL_BOOL_INFO,
 +    crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
 +    crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
 +    crate::box_default::BOX_DEFAULT_INFO,
 +    crate::cargo::CARGO_COMMON_METADATA_INFO,
 +    crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
 +    crate::cargo::NEGATIVE_FEATURE_NAMES_INFO,
 +    crate::cargo::REDUNDANT_FEATURE_NAMES_INFO,
 +    crate::cargo::WILDCARD_DEPENDENCIES_INFO,
 +    crate::casts::AS_PTR_CAST_MUT_INFO,
 +    crate::casts::AS_UNDERSCORE_INFO,
 +    crate::casts::BORROW_AS_PTR_INFO,
 +    crate::casts::CAST_ABS_TO_UNSIGNED_INFO,
 +    crate::casts::CAST_ENUM_CONSTRUCTOR_INFO,
 +    crate::casts::CAST_ENUM_TRUNCATION_INFO,
 +    crate::casts::CAST_LOSSLESS_INFO,
 +    crate::casts::CAST_NAN_TO_INT_INFO,
 +    crate::casts::CAST_POSSIBLE_TRUNCATION_INFO,
 +    crate::casts::CAST_POSSIBLE_WRAP_INFO,
 +    crate::casts::CAST_PRECISION_LOSS_INFO,
 +    crate::casts::CAST_PTR_ALIGNMENT_INFO,
 +    crate::casts::CAST_REF_TO_MUT_INFO,
 +    crate::casts::CAST_SIGN_LOSS_INFO,
 +    crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
 +    crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
 +    crate::casts::CHAR_LIT_AS_U8_INFO,
 +    crate::casts::FN_TO_NUMERIC_CAST_INFO,
 +    crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
 +    crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
 +    crate::casts::PTR_AS_PTR_INFO,
 +    crate::casts::UNNECESSARY_CAST_INFO,
 +    crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
 +    crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
 +    crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
 +    crate::collapsible_if::COLLAPSIBLE_IF_INFO,
 +    crate::comparison_chain::COMPARISON_CHAIN_INFO,
 +    crate::copies::BRANCHES_SHARING_CODE_INFO,
 +    crate::copies::IFS_SAME_COND_INFO,
 +    crate::copies::IF_SAME_THEN_ELSE_INFO,
 +    crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
 +    crate::copy_iterator::COPY_ITERATOR_INFO,
 +    crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
 +    crate::create_dir::CREATE_DIR_INFO,
 +    crate::dbg_macro::DBG_MACRO_INFO,
 +    crate::default::DEFAULT_TRAIT_ACCESS_INFO,
 +    crate::default::FIELD_REASSIGN_WITH_DEFAULT_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,
 +    crate::dereference::EXPLICIT_AUTO_DEREF_INFO,
 +    crate::dereference::EXPLICIT_DEREF_METHODS_INFO,
 +    crate::dereference::NEEDLESS_BORROW_INFO,
 +    crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
 +    crate::derivable_impls::DERIVABLE_IMPLS_INFO,
 +    crate::derive::DERIVE_HASH_XOR_EQ_INFO,
 +    crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
 +    crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
 +    crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,
 +    crate::derive::UNSAFE_DERIVE_DESERIALIZE_INFO,
 +    crate::disallowed_macros::DISALLOWED_MACROS_INFO,
 +    crate::disallowed_methods::DISALLOWED_METHODS_INFO,
 +    crate::disallowed_names::DISALLOWED_NAMES_INFO,
 +    crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
 +    crate::disallowed_types::DISALLOWED_TYPES_INFO,
 +    crate::doc::DOC_LINK_WITH_QUOTES_INFO,
 +    crate::doc::DOC_MARKDOWN_INFO,
 +    crate::doc::MISSING_ERRORS_DOC_INFO,
 +    crate::doc::MISSING_PANICS_DOC_INFO,
 +    crate::doc::MISSING_SAFETY_DOC_INFO,
 +    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,
 +    crate::empty_drop::EMPTY_DROP_INFO,
 +    crate::empty_enum::EMPTY_ENUM_INFO,
 +    crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
 +    crate::entry::MAP_ENTRY_INFO,
 +    crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
 +    crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
 +    crate::enum_variants::MODULE_INCEPTION_INFO,
 +    crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
 +    crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
 +    crate::escape::BOXED_LOCAL_INFO,
 +    crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
 +    crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
 +    crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
 +    crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
 +    crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
 +    crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
 +    crate::exit::EXIT_INFO,
 +    crate::explicit_write::EXPLICIT_WRITE_INFO,
 +    crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
 +    crate::float_literal::EXCESSIVE_PRECISION_INFO,
 +    crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
 +    crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
 +    crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
 +    crate::format::USELESS_FORMAT_INFO,
 +    crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
 +    crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
 +    crate::format_args::UNINLINED_FORMAT_ARGS_INFO,
 +    crate::format_args::UNUSED_FORMAT_SPECS_INFO,
 +    crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO,
 +    crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO,
 +    crate::format_push_string::FORMAT_PUSH_STRING_INFO,
 +    crate::formatting::POSSIBLE_MISSING_COMMA_INFO,
 +    crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
 +    crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
 +    crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
 +    crate::from_over_into::FROM_OVER_INTO_INFO,
 +    crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
 +    crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
 +    crate::functions::DOUBLE_MUST_USE_INFO,
 +    crate::functions::MISNAMED_GETTERS_INFO,
 +    crate::functions::MUST_USE_CANDIDATE_INFO,
 +    crate::functions::MUST_USE_UNIT_INFO,
 +    crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
 +    crate::functions::RESULT_LARGE_ERR_INFO,
 +    crate::functions::RESULT_UNIT_ERR_INFO,
 +    crate::functions::TOO_MANY_ARGUMENTS_INFO,
 +    crate::functions::TOO_MANY_LINES_INFO,
 +    crate::future_not_send::FUTURE_NOT_SEND_INFO,
 +    crate::if_let_mutex::IF_LET_MUTEX_INFO,
 +    crate::if_not_else::IF_NOT_ELSE_INFO,
 +    crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
 +    crate::implicit_hasher::IMPLICIT_HASHER_INFO,
 +    crate::implicit_return::IMPLICIT_RETURN_INFO,
 +    crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
 +    crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
 +    crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
 +    crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
 +    crate::indexing_slicing::INDEXING_SLICING_INFO,
 +    crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
 +    crate::infinite_iter::INFINITE_ITER_INFO,
 +    crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
 +    crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
 +    crate::inherent_to_string::INHERENT_TO_STRING_INFO,
 +    crate::inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY_INFO,
 +    crate::init_numbered_fields::INIT_NUMBERED_FIELDS_INFO,
 +    crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO,
 +    crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
 +    crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
 +    crate::int_plus_one::INT_PLUS_ONE_INFO,
 +    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::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,
 +    crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
 +    crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
 +    crate::len_zero::COMPARISON_TO_EMPTY_INFO,
 +    crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
 +    crate::len_zero::LEN_ZERO_INFO,
 +    crate::let_if_seq::USELESS_LET_IF_SEQ_INFO,
 +    crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
 +    crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
 +    crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
 +    crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
 +    crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
 +    crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
 +    crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO,
 +    crate::literal_representation::LARGE_DIGIT_GROUPS_INFO,
 +    crate::literal_representation::MISTYPED_LITERAL_SUFFIXES_INFO,
 +    crate::literal_representation::UNREADABLE_LITERAL_INFO,
 +    crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
 +    crate::loops::EMPTY_LOOP_INFO,
 +    crate::loops::EXPLICIT_COUNTER_LOOP_INFO,
 +    crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
 +    crate::loops::EXPLICIT_ITER_LOOP_INFO,
 +    crate::loops::FOR_KV_MAP_INFO,
 +    crate::loops::ITER_NEXT_LOOP_INFO,
 +    crate::loops::MANUAL_FIND_INFO,
 +    crate::loops::MANUAL_FLATTEN_INFO,
 +    crate::loops::MANUAL_MEMCPY_INFO,
 +    crate::loops::MISSING_SPIN_LOOP_INFO,
 +    crate::loops::MUT_RANGE_BOUND_INFO,
 +    crate::loops::NEEDLESS_RANGE_LOOP_INFO,
 +    crate::loops::NEVER_LOOP_INFO,
 +    crate::loops::SAME_ITEM_PUSH_INFO,
 +    crate::loops::SINGLE_ELEMENT_LOOP_INFO,
 +    crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
 +    crate::loops::WHILE_LET_LOOP_INFO,
 +    crate::loops::WHILE_LET_ON_ITERATOR_INFO,
 +    crate::macro_use::MACRO_USE_IMPORTS_INFO,
 +    crate::main_recursion::MAIN_RECURSION_INFO,
 +    crate::manual_assert::MANUAL_ASSERT_INFO,
 +    crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
 +    crate::manual_bits::MANUAL_BITS_INFO,
 +    crate::manual_clamp::MANUAL_CLAMP_INFO,
 +    crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
 +    crate::manual_let_else::MANUAL_LET_ELSE_INFO,
 +    crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
 +    crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
 +    crate::manual_retain::MANUAL_RETAIN_INFO,
 +    crate::manual_string_new::MANUAL_STRING_NEW_INFO,
 +    crate::manual_strip::MANUAL_STRIP_INFO,
 +    crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
 +    crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
 +    crate::match_result_ok::MATCH_RESULT_OK_INFO,
 +    crate::matches::COLLAPSIBLE_MATCH_INFO,
 +    crate::matches::INFALLIBLE_DESTRUCTURING_MATCH_INFO,
 +    crate::matches::MANUAL_FILTER_INFO,
 +    crate::matches::MANUAL_MAP_INFO,
 +    crate::matches::MANUAL_UNWRAP_OR_INFO,
 +    crate::matches::MATCH_AS_REF_INFO,
 +    crate::matches::MATCH_BOOL_INFO,
 +    crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
 +    crate::matches::MATCH_ON_VEC_ITEMS_INFO,
 +    crate::matches::MATCH_OVERLAPPING_ARM_INFO,
 +    crate::matches::MATCH_REF_PATS_INFO,
 +    crate::matches::MATCH_SAME_ARMS_INFO,
 +    crate::matches::MATCH_SINGLE_BINDING_INFO,
 +    crate::matches::MATCH_STR_CASE_MISMATCH_INFO,
 +    crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
 +    crate::matches::MATCH_WILD_ERR_ARM_INFO,
 +    crate::matches::NEEDLESS_MATCH_INFO,
 +    crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
 +    crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
 +    crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
 +    crate::matches::SINGLE_MATCH_INFO,
 +    crate::matches::SINGLE_MATCH_ELSE_INFO,
 +    crate::matches::TRY_ERR_INFO,
 +    crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
 +    crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
 +    crate::mem_forget::MEM_FORGET_INFO,
 +    crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
 +    crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
 +    crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
 +    crate::methods::BIND_INSTEAD_OF_MAP_INFO,
 +    crate::methods::BYTES_COUNT_TO_LEN_INFO,
 +    crate::methods::BYTES_NTH_INFO,
 +    crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO,
 +    crate::methods::CHARS_LAST_CMP_INFO,
 +    crate::methods::CHARS_NEXT_CMP_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,
 +    crate::methods::ERR_EXPECT_INFO,
 +    crate::methods::EXPECT_FUN_CALL_INFO,
 +    crate::methods::EXPECT_USED_INFO,
 +    crate::methods::EXTEND_WITH_DRAIN_INFO,
 +    crate::methods::FILETYPE_IS_FILE_INFO,
 +    crate::methods::FILTER_MAP_IDENTITY_INFO,
 +    crate::methods::FILTER_MAP_NEXT_INFO,
 +    crate::methods::FILTER_NEXT_INFO,
 +    crate::methods::FLAT_MAP_IDENTITY_INFO,
 +    crate::methods::FLAT_MAP_OPTION_INFO,
 +    crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
 +    crate::methods::GET_FIRST_INFO,
 +    crate::methods::GET_LAST_WITH_LEN_INFO,
 +    crate::methods::GET_UNWRAP_INFO,
 +    crate::methods::IMPLICIT_CLONE_INFO,
 +    crate::methods::INEFFICIENT_TO_STRING_INFO,
 +    crate::methods::INSPECT_FOR_EACH_INFO,
 +    crate::methods::INTO_ITER_ON_REF_INFO,
 +    crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
 +    crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
 +    crate::methods::ITER_CLONED_COLLECT_INFO,
 +    crate::methods::ITER_COUNT_INFO,
 +    crate::methods::ITER_KV_MAP_INFO,
 +    crate::methods::ITER_NEXT_SLICE_INFO,
 +    crate::methods::ITER_NTH_INFO,
 +    crate::methods::ITER_NTH_ZERO_INFO,
 +    crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO,
 +    crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
 +    crate::methods::ITER_OVEREAGER_CLONED_INFO,
 +    crate::methods::ITER_SKIP_NEXT_INFO,
 +    crate::methods::ITER_WITH_DRAIN_INFO,
 +    crate::methods::MANUAL_FILTER_MAP_INFO,
 +    crate::methods::MANUAL_FIND_MAP_INFO,
 +    crate::methods::MANUAL_OK_OR_INFO,
 +    crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
 +    crate::methods::MANUAL_SPLIT_ONCE_INFO,
 +    crate::methods::MANUAL_STR_REPEAT_INFO,
 +    crate::methods::MAP_CLONE_INFO,
 +    crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
 +    crate::methods::MAP_ERR_IGNORE_INFO,
 +    crate::methods::MAP_FLATTEN_INFO,
 +    crate::methods::MAP_IDENTITY_INFO,
 +    crate::methods::MAP_UNWRAP_OR_INFO,
 +    crate::methods::MUT_MUTEX_LOCK_INFO,
 +    crate::methods::NAIVE_BYTECOUNT_INFO,
 +    crate::methods::NEEDLESS_COLLECT_INFO,
 +    crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
 +    crate::methods::NEEDLESS_OPTION_TAKE_INFO,
 +    crate::methods::NEEDLESS_SPLITN_INFO,
 +    crate::methods::NEW_RET_NO_SELF_INFO,
 +    crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO,
 +    crate::methods::NO_EFFECT_REPLACE_INFO,
 +    crate::methods::OBFUSCATED_IF_ELSE_INFO,
 +    crate::methods::OK_EXPECT_INFO,
 +    crate::methods::OPTION_AS_REF_DEREF_INFO,
 +    crate::methods::OPTION_FILTER_MAP_INFO,
 +    crate::methods::OPTION_MAP_OR_NONE_INFO,
 +    crate::methods::OR_FUN_CALL_INFO,
 +    crate::methods::OR_THEN_UNWRAP_INFO,
 +    crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
 +    crate::methods::RANGE_ZIP_WITH_LEN_INFO,
 +    crate::methods::REPEAT_ONCE_INFO,
 +    crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
 +    crate::methods::SEARCH_IS_SOME_INFO,
 +    crate::methods::SEEK_FROM_CURRENT_INFO,
 +    crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
 +    crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO,
 +    crate::methods::SINGLE_CHAR_ADD_STR_INFO,
 +    crate::methods::SINGLE_CHAR_PATTERN_INFO,
 +    crate::methods::SKIP_WHILE_NEXT_INFO,
 +    crate::methods::STABLE_SORT_PRIMITIVE_INFO,
 +    crate::methods::STRING_EXTEND_CHARS_INFO,
 +    crate::methods::SUSPICIOUS_MAP_INFO,
 +    crate::methods::SUSPICIOUS_SPLITN_INFO,
 +    crate::methods::SUSPICIOUS_TO_OWNED_INFO,
 +    crate::methods::UNINIT_ASSUMED_INIT_INFO,
 +    crate::methods::UNIT_HASH_INFO,
 +    crate::methods::UNNECESSARY_FILTER_MAP_INFO,
 +    crate::methods::UNNECESSARY_FIND_MAP_INFO,
 +    crate::methods::UNNECESSARY_FOLD_INFO,
 +    crate::methods::UNNECESSARY_JOIN_INFO,
 +    crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
 +    crate::methods::UNNECESSARY_SORT_BY_INFO,
 +    crate::methods::UNNECESSARY_TO_OWNED_INFO,
 +    crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
 +    crate::methods::UNWRAP_USED_INFO,
 +    crate::methods::USELESS_ASREF_INFO,
 +    crate::methods::VEC_RESIZE_TO_ZERO_INFO,
 +    crate::methods::VERBOSE_FILE_READS_INFO,
 +    crate::methods::WRONG_SELF_CONVENTION_INFO,
 +    crate::methods::ZST_OFFSET_INFO,
 +    crate::minmax::MIN_MAX_INFO,
 +    crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
 +    crate::misc::TOPLEVEL_REF_ARG_INFO,
 +    crate::misc::USED_UNDERSCORE_BINDING_INFO,
 +    crate::misc::ZERO_PTR_INFO,
 +    crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
 +    crate::misc_early::DOUBLE_NEG_INFO,
 +    crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
 +    crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
 +    crate::misc_early::REDUNDANT_PATTERN_INFO,
 +    crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
 +    crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
 +    crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
 +    crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
 +    crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
 +    crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
 +    crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
 +    crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
 +    crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
 +    crate::missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS_INFO,
 +    crate::missing_trait_methods::MISSING_TRAIT_METHODS_INFO,
 +    crate::mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION_INFO,
 +    crate::mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION_INFO,
 +    crate::module_style::MOD_MODULE_FILES_INFO,
 +    crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
 +    crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
 +    crate::mut_key::MUTABLE_KEY_TYPE_INFO,
 +    crate::mut_mut::MUT_MUT_INFO,
 +    crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
 +    crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO,
 +    crate::mutex_atomic::MUTEX_ATOMIC_INFO,
 +    crate::mutex_atomic::MUTEX_INTEGER_INFO,
 +    crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
 +    crate::needless_bool::BOOL_COMPARISON_INFO,
 +    crate::needless_bool::NEEDLESS_BOOL_INFO,
 +    crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
 +    crate::needless_continue::NEEDLESS_CONTINUE_INFO,
 +    crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
 +    crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
 +    crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
 +    crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
 +    crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
 +    crate::needless_update::NEEDLESS_UPDATE_INFO,
 +    crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
 +    crate::neg_multiply::NEG_MULTIPLY_INFO,
 +    crate::new_without_default::NEW_WITHOUT_DEFAULT_INFO,
 +    crate::no_effect::NO_EFFECT_INFO,
 +    crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
 +    crate::no_effect::UNNECESSARY_OPERATION_INFO,
 +    crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
 +    crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
 +    crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
 +    crate::non_expressive_names::MANY_SINGLE_CHAR_NAMES_INFO,
 +    crate::non_expressive_names::SIMILAR_NAMES_INFO,
 +    crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
 +    crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
 +    crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
 +    crate::octal_escapes::OCTAL_ESCAPES_INFO,
 +    crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
 +    crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,
 +    crate::operators::ARITHMETIC_SIDE_EFFECTS_INFO,
 +    crate::operators::ASSIGN_OP_PATTERN_INFO,
 +    crate::operators::BAD_BIT_MASK_INFO,
 +    crate::operators::CMP_NAN_INFO,
 +    crate::operators::CMP_OWNED_INFO,
 +    crate::operators::DOUBLE_COMPARISONS_INFO,
 +    crate::operators::DURATION_SUBSEC_INFO,
 +    crate::operators::EQ_OP_INFO,
 +    crate::operators::ERASING_OP_INFO,
 +    crate::operators::FLOAT_ARITHMETIC_INFO,
 +    crate::operators::FLOAT_CMP_INFO,
 +    crate::operators::FLOAT_CMP_CONST_INFO,
 +    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,
 +    crate::operators::MODULO_ONE_INFO,
 +    crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
 +    crate::operators::OP_REF_INFO,
 +    crate::operators::PTR_EQ_INFO,
 +    crate::operators::SELF_ASSIGNMENT_INFO,
 +    crate::operators::VERBOSE_BIT_MASK_INFO,
 +    crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
 +    crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
 +    crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
 +    crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
 +    crate::panic_unimplemented::PANIC_INFO,
 +    crate::panic_unimplemented::TODO_INFO,
 +    crate::panic_unimplemented::UNIMPLEMENTED_INFO,
 +    crate::panic_unimplemented::UNREACHABLE_INFO,
 +    crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
 +    crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
 +    crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
 +    crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
 +    crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
 +    crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
 +    crate::precedence::PRECEDENCE_INFO,
 +    crate::ptr::CMP_NULL_INFO,
 +    crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
 +    crate::ptr::MUT_FROM_REF_INFO,
 +    crate::ptr::PTR_ARG_INFO,
 +    crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
 +    crate::pub_use::PUB_USE_INFO,
 +    crate::question_mark::QUESTION_MARK_INFO,
 +    crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
 +    crate::ranges::RANGE_MINUS_ONE_INFO,
 +    crate::ranges::RANGE_PLUS_ONE_INFO,
 +    crate::ranges::REVERSED_EMPTY_RANGES_INFO,
 +    crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
 +    crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
 +    crate::redundant_clone::REDUNDANT_CLONE_INFO,
 +    crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
 +    crate::redundant_else::REDUNDANT_ELSE_INFO,
 +    crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
 +    crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
 +    crate::redundant_slicing::DEREF_BY_SLICING_INFO,
 +    crate::redundant_slicing::REDUNDANT_SLICING_INFO,
 +    crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
 +    crate::ref_option_ref::REF_OPTION_REF_INFO,
 +    crate::reference::DEREF_ADDROF_INFO,
 +    crate::regex::INVALID_REGEX_INFO,
 +    crate::regex::TRIVIAL_REGEX_INFO,
 +    crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
 +    crate::returns::LET_AND_RETURN_INFO,
 +    crate::returns::NEEDLESS_RETURN_INFO,
 +    crate::same_name_method::SAME_NAME_METHOD_INFO,
 +    crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
++    crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
++    crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
 +    crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
 +    crate::serde_api::SERDE_API_MISUSE_INFO,
 +    crate::shadow::SHADOW_REUSE_INFO,
 +    crate::shadow::SHADOW_SAME_INFO,
 +    crate::shadow::SHADOW_UNRELATED_INFO,
 +    crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
 +    crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
 +    crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
 +    crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
 +    crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
 +    crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
 +    crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO,
 +    crate::strings::STRING_ADD_INFO,
 +    crate::strings::STRING_ADD_ASSIGN_INFO,
 +    crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO,
 +    crate::strings::STRING_LIT_AS_BYTES_INFO,
 +    crate::strings::STRING_SLICE_INFO,
 +    crate::strings::STRING_TO_STRING_INFO,
 +    crate::strings::STR_TO_STRING_INFO,
 +    crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
 +    crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
 +    crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
 +    crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
 +    crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
 +    crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
 +    crate::swap::ALMOST_SWAPPED_INFO,
 +    crate::swap::MANUAL_SWAP_INFO,
 +    crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
 +    crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
 +    crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
 +    crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
 +    crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
 +    crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
 +    crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
 +    crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
 +    crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
 +    crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
 +    crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
 +    crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
 +    crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
 +    crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
 +    crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
 +    crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
 +    crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
 +    crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO,
 +    crate::transmute::TRANSMUTING_NULL_INFO,
 +    crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
 +    crate::transmute::USELESS_TRANSMUTE_INFO,
 +    crate::transmute::WRONG_TRANSMUTE_INFO,
 +    crate::types::BORROWED_BOX_INFO,
 +    crate::types::BOX_COLLECTION_INFO,
 +    crate::types::LINKEDLIST_INFO,
 +    crate::types::OPTION_OPTION_INFO,
 +    crate::types::RC_BUFFER_INFO,
 +    crate::types::RC_MUTEX_INFO,
 +    crate::types::REDUNDANT_ALLOCATION_INFO,
 +    crate::types::TYPE_COMPLEXITY_INFO,
 +    crate::types::VEC_BOX_INFO,
 +    crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
 +    crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
 +    crate::unicode::INVISIBLE_CHARACTERS_INFO,
 +    crate::unicode::NON_ASCII_LITERAL_INFO,
 +    crate::unicode::UNICODE_NOT_NFC_INFO,
 +    crate::uninit_vec::UNINIT_VEC_INFO,
 +    crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
 +    crate::unit_types::LET_UNIT_VALUE_INFO,
 +    crate::unit_types::UNIT_ARG_INFO,
 +    crate::unit_types::UNIT_CMP_INFO,
 +    crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
 +    crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
 +    crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
 +    crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
 +    crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
 +    crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
 +    crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,
 +    crate::unused_async::UNUSED_ASYNC_INFO,
 +    crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
 +    crate::unused_peekable::UNUSED_PEEKABLE_INFO,
 +    crate::unused_rounding::UNUSED_ROUNDING_INFO,
 +    crate::unused_self::UNUSED_SELF_INFO,
 +    crate::unused_unit::UNUSED_UNIT_INFO,
 +    crate::unwrap::PANICKING_UNWRAP_INFO,
 +    crate::unwrap::UNNECESSARY_UNWRAP_INFO,
 +    crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
 +    crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
 +    crate::use_self::USE_SELF_INFO,
 +    crate::useless_conversion::USELESS_CONVERSION_INFO,
 +    crate::vec::USELESS_VEC_INFO,
 +    crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
 +    crate::wildcard_imports::ENUM_GLOB_USE_INFO,
 +    crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
 +    crate::write::PRINTLN_EMPTY_STRING_INFO,
 +    crate::write::PRINT_LITERAL_INFO,
 +    crate::write::PRINT_STDERR_INFO,
 +    crate::write::PRINT_STDOUT_INFO,
 +    crate::write::PRINT_WITH_NEWLINE_INFO,
 +    crate::write::USE_DEBUG_INFO,
 +    crate::write::WRITELN_EMPTY_STRING_INFO,
 +    crate::write::WRITE_LITERAL_INFO,
 +    crate::write::WRITE_WITH_NEWLINE_INFO,
 +    crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
 +    crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
 +];
index 31183266acfcba44236911f54cd37d25113dc8ef,0000000000000000000000000000000000000000..7b43d8ccc67d1fec92a5be0389860e9c8c6658a5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1638 -1,0 +1,1643 @@@
-             ty::Alias(ty::Projection, _) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-             ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::Opaque, ..) | ty::Placeholder(_) | ty::Dynamic(..) => {
-                 Position::ReborrowStable(precedence).into()
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 +use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 +use clippy_utils::sugg::has_enclosing_paren;
 +use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
 +use clippy_utils::{
 +    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
 +};
 +
 +use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 +use rustc_data_structures::fx::FxIndexMap;
 +use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_ty, Visitor};
 +use rustc_hir::{
 +    self as hir,
 +    def_id::{DefId, LocalDefId},
 +    BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem,
 +    ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
 +    TraitItemKind, TyKind, UnOp,
 +};
 +use rustc_index::bit_set::BitSet;
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::mir::{Rvalue, StatementKind};
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 +use rustc_middle::ty::{
 +    self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
 +    ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
 +};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{symbol::sym, Span, Symbol};
 +use rustc_trait_selection::infer::InferCtxtExt as _;
 +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
 +use std::collections::VecDeque;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for explicit `deref()` or `deref_mut()` method calls.
 +    ///
 +    /// ### Why is this bad?
 +    /// Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
 +    /// when not part of a method chain.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::ops::Deref;
 +    /// let a: &mut String = &mut String::from("foo");
 +    /// let b: &str = a.deref();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let a: &mut String = &mut String::from("foo");
 +    /// let b = &*a;
 +    /// ```
 +    ///
 +    /// This lint excludes:
 +    /// ```rust,ignore
 +    /// let _ = d.unwrap().deref();
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub EXPLICIT_DEREF_METHODS,
 +    pedantic,
 +    "Explicit use of deref or deref_mut method while not in a method chain."
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for address of operations (`&`) that are going to
 +    /// be dereferenced immediately by the compiler.
 +    ///
 +    /// ### Why is this bad?
 +    /// Suggests that the receiver of the expression borrows
 +    /// the expression.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn fun(_a: &i32) {}
 +    ///
 +    /// let x: &i32 = &&&&&&5;
 +    /// fun(&x);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # fn fun(_a: &i32) {}
 +    /// let x: &i32 = &5;
 +    /// fun(x);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEEDLESS_BORROW,
 +    style,
 +    "taking a reference that is going to be automatically dereferenced"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `ref` bindings which create a reference to a reference.
 +    ///
 +    /// ### Why is this bad?
 +    /// The address-of operator at the use site is clearer about the need for a reference.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = Some("");
 +    /// if let Some(ref x) = x {
 +    ///     // use `x` here
 +    /// }
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = Some("");
 +    /// if let Some(x) = x {
 +    ///     // use `&x` here
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub REF_BINDING_TO_REFERENCE,
 +    pedantic,
 +    "`ref` binding to a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for dereferencing expressions which would be covered by auto-deref.
 +    ///
 +    /// ### Why is this bad?
 +    /// This unnecessarily complicates the code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = String::new();
 +    /// let y: &str = &*x;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = String::new();
 +    /// let y: &str = &x;
 +    /// ```
 +    #[clippy::version = "1.64.0"]
 +    pub EXPLICIT_AUTO_DEREF,
 +    complexity,
 +    "dereferencing when the compiler would automatically dereference"
 +}
 +
 +impl_lint_pass!(Dereferencing<'_> => [
 +    EXPLICIT_DEREF_METHODS,
 +    NEEDLESS_BORROW,
 +    REF_BINDING_TO_REFERENCE,
 +    EXPLICIT_AUTO_DEREF,
 +]);
 +
 +#[derive(Default)]
 +pub struct Dereferencing<'tcx> {
 +    state: Option<(State, StateData)>,
 +
 +    // While parsing a `deref` method call in ufcs form, the path to the function is itself an
 +    // expression. This is to store the id of that expression so it can be skipped when
 +    // `check_expr` is called for it.
 +    skip_expr: Option<HirId>,
 +
 +    /// The body the first local was found in. Used to emit lints when the traversal of the body has
 +    /// been finished. Note we can't lint at the end of every body as they can be nested within each
 +    /// other.
 +    current_body: Option<BodyId>,
 +
 +    /// The list of locals currently being checked by the lint.
 +    /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
 +    /// This is needed for or patterns where one of the branches can be linted, but another can not
 +    /// be.
 +    ///
 +    /// e.g. `m!(x) | Foo::Bar(ref x)`
 +    ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 +
 +    /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by
 +    /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead
 +    /// be moved.
 +    possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 +
 +    // `IntoIterator` for arrays requires Rust 1.53.
 +    msrv: Msrv,
 +}
 +
 +impl<'tcx> Dereferencing<'tcx> {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        Self {
 +            msrv,
 +            ..Dereferencing::default()
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +struct StateData {
 +    /// Span of the top level expression
 +    span: Span,
 +    hir_id: HirId,
 +    position: Position,
 +}
 +
 +#[derive(Debug)]
 +struct DerefedBorrow {
 +    count: usize,
 +    msg: &'static str,
 +    snip_expr: Option<HirId>,
 +}
 +
 +#[derive(Debug)]
 +enum State {
 +    // Any number of deref method calls.
 +    DerefMethod {
 +        // The number of calls in a sequence which changed the referenced type
 +        ty_changed_count: usize,
 +        is_final_ufcs: bool,
 +        /// The required mutability
 +        target_mut: Mutability,
 +    },
 +    DerefedBorrow(DerefedBorrow),
 +    ExplicitDeref {
 +        mutability: Option<Mutability>,
 +    },
 +    ExplicitDerefField {
 +        name: Symbol,
 +    },
 +    Reborrow {
 +        mutability: Mutability,
 +    },
 +    Borrow {
 +        mutability: Mutability,
 +    },
 +}
 +
 +// A reference operation considered by this lint pass
 +enum RefOp {
 +    Method(Mutability),
 +    Deref,
 +    AddrOf(Mutability),
 +}
 +
 +struct RefPat {
 +    /// Whether every usage of the binding is dereferenced.
 +    always_deref: bool,
 +    /// The spans of all the ref bindings for this local.
 +    spans: Vec<Span>,
 +    /// The applicability of this suggestion.
 +    app: Applicability,
 +    /// All the replacements which need to be made.
 +    replacements: Vec<(Span, String)>,
 +    /// The [`HirId`] that the lint should be emitted at.
 +    hir_id: HirId,
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
 +    #[expect(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // Skip path expressions from deref calls. e.g. `Deref::deref(e)`
 +        if Some(expr.hir_id) == self.skip_expr.take() {
 +            return;
 +        }
 +
 +        if let Some(local) = path_to_local(expr) {
 +            self.check_local_usage(cx, expr, local);
 +        }
 +
 +        // Stop processing sub expressions when a macro call is seen
 +        if expr.span.from_expansion() {
 +            if let Some((state, data)) = self.state.take() {
 +                report(cx, expr, state, data);
 +            }
 +            return;
 +        }
 +
 +        let typeck = cx.typeck_results();
 +        let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
 +            // The whole chain of reference operations has been seen
 +            if let Some((state, data)) = self.state.take() {
 +                report(cx, expr, state, data);
 +            }
 +            return;
 +        };
 +
 +        match (self.state.take(), kind) {
 +            (None, kind) => {
 +                let expr_ty = typeck.expr_ty(expr);
 +                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
 +                match kind {
 +                    RefOp::Deref => {
 +                        let sub_ty = typeck.expr_ty(sub_expr);
 +                        if let Position::FieldAccess {
 +                            name,
 +                            of_union: false,
 +                        } = position
 +                            && !ty_contains_field(sub_ty, name)
 +                        {
 +                            self.state = Some((
 +                                State::ExplicitDerefField { name },
 +                                StateData { span: expr.span, hir_id: expr.hir_id, position },
 +                            ));
 +                        } else if position.is_deref_stable() && sub_ty.is_ref() {
 +                            self.state = Some((
 +                                State::ExplicitDeref { mutability: None },
 +                                StateData { span: expr.span, hir_id: expr.hir_id, position },
 +                            ));
 +                        }
 +                    },
 +                    RefOp::Method(target_mut)
 +                        if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
 +                            && position.lint_explicit_deref() =>
 +                    {
 +                        let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
 +                        self.state = Some((
 +                            State::DerefMethod {
 +                                ty_changed_count,
 +                                is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
 +                                target_mut,
 +                            },
 +                            StateData {
 +                                span: expr.span,
 +                                hir_id: expr.hir_id,
 +                                position,
 +                            },
 +                        ));
 +                    },
 +                    RefOp::AddrOf(mutability) => {
 +                        // Find the number of times the borrow is auto-derefed.
 +                        let mut iter = adjustments.iter();
 +                        let mut deref_count = 0usize;
 +                        let next_adjust = loop {
 +                            match iter.next() {
 +                                Some(adjust) => {
 +                                    if !matches!(adjust.kind, Adjust::Deref(_)) {
 +                                        break Some(adjust);
 +                                    } else if !adjust.target.is_ref() {
 +                                        deref_count += 1;
 +                                        break iter.next();
 +                                    }
 +                                    deref_count += 1;
 +                                },
 +                                None => break None,
 +                            };
 +                        };
 +
 +                        // Determine the required number of references before any can be removed. In all cases the
 +                        // reference made by the current expression will be removed. After that there are four cases to
 +                        // handle.
 +                        //
 +                        // 1. Auto-borrow will trigger in the current position, so no further references are required.
 +                        // 2. Auto-deref ends at a reference, or the underlying type, so one extra needs to be left to
 +                        //    handle the automatically inserted re-borrow.
 +                        // 3. Auto-deref hits a user-defined `Deref` impl, so at least one reference needs to exist to
 +                        //    start auto-deref.
 +                        // 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow
 +                        //    adjustments will not be inserted automatically, then leave one further reference to avoid
 +                        //    moving a mutable borrow.
 +                        //    e.g.
 +                        //        fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
 +                        //            let x = match x {
 +                        //                // Removing the borrow will cause `x` to be moved
 +                        //                Some(x) => &mut *x,
 +                        //                None => y
 +                        //            };
 +                        //        }
 +                        let deref_msg =
 +                            "this expression creates a reference which is immediately dereferenced by the compiler";
 +                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
 +                        let impl_msg = "the borrowed expression implements the required traits";
 +
 +                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
 +                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
 +                        } else if let Position::ImplArg(hir_id) = position {
 +                            (0, impl_msg, Some(hir_id))
 +                        } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
 +                            next_adjust.map(|a| &a.kind)
 +                        {
 +                            if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
 +                            {
 +                                (3, deref_msg, None)
 +                            } else {
 +                                (2, deref_msg, None)
 +                            }
 +                        } else {
 +                            (2, deref_msg, None)
 +                        };
 +
 +                        if deref_count >= required_refs {
 +                            self.state = Some((
 +                                State::DerefedBorrow(DerefedBorrow {
 +                                    // One of the required refs is for the current borrow expression, the remaining ones
 +                                    // can't be removed without breaking the code. See earlier comment.
 +                                    count: deref_count - required_refs,
 +                                    msg,
 +                                    snip_expr,
 +                                }),
 +                                StateData {
 +                                    span: expr.span,
 +                                    hir_id: expr.hir_id,
 +                                    position,
 +                                },
 +                            ));
 +                        } else if position.is_deref_stable()
 +                            // Auto-deref doesn't combine with other adjustments
 +                            && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
 +                            && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
 +                        {
 +                            self.state = Some((
 +                                State::Borrow { mutability },
 +                                StateData {
 +                                    span: expr.span,
 +                                    hir_id: expr.hir_id,
 +                                    position,
 +                                },
 +                            ));
 +                        }
 +                    },
 +                    RefOp::Method(..) => (),
 +                }
 +            },
 +            (
 +                Some((
 +                    State::DerefMethod {
 +                        target_mut,
 +                        ty_changed_count,
 +                        ..
 +                    },
 +                    data,
 +                )),
 +                RefOp::Method(_),
 +            ) => {
 +                self.state = Some((
 +                    State::DerefMethod {
 +                        ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) {
 +                            ty_changed_count
 +                        } else {
 +                            ty_changed_count + 1
 +                        },
 +                        is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
 +                        target_mut,
 +                    },
 +                    data,
 +                ));
 +            },
 +            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
 +                self.state = Some((
 +                    State::DerefedBorrow(DerefedBorrow {
 +                        count: state.count - 1,
 +                        ..state
 +                    }),
 +                    data,
 +                ));
 +            },
 +            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
 +                let position = data.position;
 +                report(cx, expr, State::DerefedBorrow(state), data);
 +                if position.is_deref_stable() {
 +                    self.state = Some((
 +                        State::Borrow { mutability },
 +                        StateData {
 +                            span: expr.span,
 +                            hir_id: expr.hir_id,
 +                            position,
 +                        },
 +                    ));
 +                }
 +            },
 +            (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
 +                let position = data.position;
 +                report(cx, expr, State::DerefedBorrow(state), data);
 +                if let Position::FieldAccess{name, ..} = position
 +                    && !ty_contains_field(typeck.expr_ty(sub_expr), name)
 +                {
 +                    self.state = Some((
 +                        State::ExplicitDerefField { name },
 +                        StateData { span: expr.span, hir_id: expr.hir_id, position },
 +                    ));
 +                } else if position.is_deref_stable() {
 +                    self.state = Some((
 +                        State::ExplicitDeref { mutability: None },
 +                        StateData { span: expr.span, hir_id: expr.hir_id, position },
 +                    ));
 +                }
 +            },
 +
 +            (Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
 +                if typeck.expr_ty(sub_expr).is_ref() {
 +                    self.state = Some((State::Reborrow { mutability }, data));
 +                } else {
 +                    self.state = Some((
 +                        State::ExplicitDeref {
 +                            mutability: Some(mutability),
 +                        },
 +                        data,
 +                    ));
 +                }
 +            },
 +            (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
 +                self.state = Some((
 +                    State::ExplicitDeref {
 +                        mutability: Some(mutability),
 +                    },
 +                    data,
 +                ));
 +            },
 +            (state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => {
 +                self.state = state;
 +            },
 +            (Some((State::ExplicitDerefField { name }, data)), RefOp::Deref)
 +                if !ty_contains_field(typeck.expr_ty(sub_expr), name) =>
 +            {
 +                self.state = Some((State::ExplicitDerefField { name }, data));
 +            },
 +
 +            (Some((state, data)), _) => report(cx, expr, state, data),
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind {
 +            if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
 +                // This binding id has been seen before. Add this pattern to the list of changes.
 +                if let Some(prev_pat) = opt_prev_pat {
 +                    if pat.span.from_expansion() {
 +                        // Doesn't match the context of the previous pattern. Can't lint here.
 +                        *opt_prev_pat = None;
 +                    } else {
 +                        prev_pat.spans.push(pat.span);
 +                        prev_pat.replacements.push((
 +                            pat.span,
 +                            snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
 +                                .0
 +                                .into(),
 +                        ));
 +                    }
 +                }
 +                return;
 +            }
 +
 +            if_chain! {
 +                if !pat.span.from_expansion();
 +                if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
 +                // only lint immutable refs, because borrowed `&mut T` cannot be moved out
 +                if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
 +                then {
 +                    let mut app = Applicability::MachineApplicable;
 +                    let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
 +                    self.current_body = self.current_body.or(cx.enclosing_body);
 +                    self.ref_locals.insert(
 +                        id,
 +                        Some(RefPat {
 +                            always_deref: true,
 +                            spans: vec![pat.span],
 +                            app,
 +                            replacements: vec![(pat.span, snip.into())],
 +                            hir_id: pat.hir_id,
 +                        }),
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
 +        if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| {
 +            local_def_id == cx.tcx.hir().body_owner_def_id(body.id())
 +        }) {
 +            self.possible_borrowers.pop();
 +        }
 +
 +        if Some(body.id()) == self.current_body {
 +            for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
 +                let replacements = pat.replacements;
 +                let app = pat.app;
 +                let lint = if pat.always_deref {
 +                    NEEDLESS_BORROW
 +                } else {
 +                    REF_BINDING_TO_REFERENCE
 +                };
 +                span_lint_hir_and_then(
 +                    cx,
 +                    lint,
 +                    pat.hir_id,
 +                    pat.spans,
 +                    "this pattern creates a reference to a reference",
 +                    |diag| {
 +                        diag.multipart_suggestion("try this", replacements, app);
 +                    },
 +                );
 +            }
 +            self.current_body = None;
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +fn try_parse_ref_op<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    typeck: &'tcx TypeckResults<'_>,
 +    expr: &'tcx Expr<'_>,
 +) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
 +    let (def_id, arg) = match expr.kind {
 +        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(path),
 +                hir_id,
 +                ..
 +            },
 +            [arg],
 +        ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
 +        ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
 +            return Some((RefOp::Deref, sub_expr));
 +        },
 +        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
 +        _ => return None,
 +    };
 +    if tcx.is_diagnostic_item(sym::deref_method, def_id) {
 +        Some((RefOp::Method(Mutability::Not), arg))
 +    } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
 +        Some((RefOp::Method(Mutability::Mut), arg))
 +    } else {
 +        None
 +    }
 +}
 +
 +// Checks whether the type for a deref call actually changed the type, not just the mutability of
 +// the reference.
 +fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
 +    match (result_ty.kind(), arg_ty.kind()) {
 +        (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => result_ty == arg_ty,
 +
 +        // The result type for a deref method is always a reference
 +        // Not matching the previous pattern means the argument type is not a reference
 +        // This means that the type did change
 +        _ => false,
 +    }
 +}
 +
 +/// The position of an expression relative to it's parent.
 +#[derive(Clone, Copy, Debug)]
 +enum Position {
 +    MethodReceiver,
 +    /// The method is defined on a reference type. e.g. `impl Foo for &T`
 +    MethodReceiverRefImpl,
 +    Callee,
 +    ImplArg(HirId),
 +    FieldAccess {
 +        name: Symbol,
 +        of_union: bool,
 +    }, // union fields cannot be auto borrowed
 +    Postfix,
 +    Deref,
 +    /// Any other location which will trigger auto-deref to a specific time.
 +    /// Contains the precedence of the parent expression and whether the target type is sized.
 +    DerefStable(i8, bool),
 +    /// Any other location which will trigger auto-reborrowing.
 +    /// Contains the precedence of the parent expression.
 +    ReborrowStable(i8),
 +    /// Contains the precedence of the parent expression.
 +    Other(i8),
 +}
 +impl Position {
 +    fn is_deref_stable(self) -> bool {
 +        matches!(self, Self::DerefStable(..))
 +    }
 +
 +    fn is_reborrow_stable(self) -> bool {
 +        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
 +    }
 +
 +    fn can_auto_borrow(self) -> bool {
 +        matches!(
 +            self,
 +            Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
 +        )
 +    }
 +
 +    fn lint_explicit_deref(self) -> bool {
 +        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
 +    }
 +
 +    fn precedence(self) -> i8 {
 +        match self {
 +            Self::MethodReceiver
 +            | Self::MethodReceiverRefImpl
 +            | Self::Callee
 +            | Self::FieldAccess { .. }
 +            | Self::Postfix => PREC_POSTFIX,
 +            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
 +            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
 +        }
 +    }
 +}
 +
 +/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
 +/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
 +/// locations as those follow different rules.
 +#[expect(clippy::too_many_lines)]
 +fn walk_parents<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 +    e: &'tcx Expr<'_>,
 +    msrv: &Msrv,
 +) -> (Position, &'tcx [Adjustment<'tcx>]) {
 +    let mut adjustments = [].as_slice();
 +    let mut precedence = 0i8;
 +    let ctxt = e.span.ctxt();
 +    let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| {
 +        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
 +        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
 +            adjustments = cx.typeck_results().expr_adjustments(e);
 +        }
 +        match parent {
 +            Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
 +                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
 +            },
 +            Node::Item(&Item {
 +                kind: ItemKind::Static(..) | ItemKind::Const(..),
 +                owner_id,
 +                span,
 +                ..
 +            })
 +            | Node::TraitItem(&TraitItem {
 +                kind: TraitItemKind::Const(..),
 +                owner_id,
 +                span,
 +                ..
 +            })
 +            | Node::ImplItem(&ImplItem {
 +                kind: ImplItemKind::Const(..),
 +                owner_id,
 +                span,
 +                ..
 +            }) if span.ctxt() == ctxt => {
 +                let ty = cx.tcx.type_of(owner_id.def_id);
 +                Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
 +            },
 +
 +            Node::Item(&Item {
 +                kind: ItemKind::Fn(..),
 +                owner_id,
 +                span,
 +                ..
 +            })
 +            | Node::TraitItem(&TraitItem {
 +                kind: TraitItemKind::Fn(..),
 +                owner_id,
 +                span,
 +                ..
 +            })
 +            | Node::ImplItem(&ImplItem {
 +                kind: ImplItemKind::Fn(..),
 +                owner_id,
 +                span,
 +                ..
 +            }) if span.ctxt() == ctxt => {
 +                let output = cx
 +                    .tcx
 +                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
 +                Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
 +            },
 +
 +            Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
 +                Some(Expr {
 +                    hir_id,
 +                    kind: ExprKind::Struct(path, ..),
 +                    ..
 +                }) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
 +                    .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
 +                    .map(|field_def| {
 +                        ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg()
 +                    }),
 +                _ => None,
 +            },
 +
 +            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
 +                ExprKind::Ret(_) => {
 +                    let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
 +                    Some(
 +                        if let Node::Expr(
 +                            closure_expr @ Expr {
 +                                kind: ExprKind::Closure(closure),
 +                                ..
 +                            },
 +                        ) = cx.tcx.hir().get(owner_id)
 +                        {
 +                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
 +                        } else {
 +                            let output = cx
 +                                .tcx
 +                                .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
 +                            ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
 +                        },
 +                    )
 +                },
 +                ExprKind::Closure(closure) => Some(closure_result_position(
 +                    cx,
 +                    closure,
 +                    cx.typeck_results().expr_ty(parent),
 +                    precedence,
 +                )),
 +                ExprKind::Call(func, _) if func.hir_id == child_id => {
 +                    (child_id == e.hir_id).then_some(Position::Callee)
 +                },
 +                ExprKind::Call(func, args) => args
 +                    .iter()
 +                    .position(|arg| arg.hir_id == child_id)
 +                    .zip(expr_sig(cx, func))
 +                    .and_then(|(i, sig)| {
 +                        sig.input_with_hir(i).map(|(hir_ty, ty)| {
 +                            match hir_ty {
 +                                // Type inference for closures can depend on how they're called. Only go by the explicit
 +                                // types here.
 +                                Some(hir_ty) => {
 +                                    binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
 +                                },
 +                                None => {
 +                                    // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
 +                                    // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
 +                                    if e.hir_id == child_id
 +                                        && !call_is_qualified(func)
 +                                        && let ty::Param(param_ty) = ty.skip_binder().kind()
 +                                    {
 +                                        needless_borrow_impl_arg_position(
 +                                            cx,
 +                                            possible_borrowers,
 +                                            parent,
 +                                            i,
 +                                            *param_ty,
 +                                            e,
 +                                            precedence,
 +                                            msrv,
 +                                        )
 +                                    } else {
 +                                        ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
 +                                            .position_for_arg()
 +                                    }
 +                                },
 +                            }
 +                        })
 +                    }),
 +                ExprKind::MethodCall(method, receiver, args, _) => {
 +                    let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
 +                    if receiver.hir_id == child_id {
 +                        // Check for calls to trait methods where the trait is implemented on a reference.
 +                        // Two cases need to be handled:
 +                        // * `self` methods on `&T` will never have auto-borrow
 +                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
 +                        //   priority.
 +                        if e.hir_id != child_id {
 +                            return Some(Position::ReborrowStable(precedence))
 +                        } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
 +                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
 +                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
 +                            && let subs = cx
 +                                .typeck_results()
 +                                .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
 +                            && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
 +                                // Trait methods taking `&self`
 +                                sub_ty
 +                            } else {
 +                                // Trait methods taking `self`
 +                                arg_ty
 +                            } && impl_ty.is_ref()
 +                            && let infcx = cx.tcx.infer_ctxt().build()
 +                            && infcx
 +                                .type_implements_trait(
 +                                    trait_id,
 +                                    [impl_ty.into()].into_iter().chain(subs.iter().copied()),
 +                                    cx.param_env,
 +                                )
 +                                .must_apply_modulo_regions()
 +                        {
 +                            return Some(Position::MethodReceiverRefImpl)
 +                        }
 +                        return Some(Position::MethodReceiver);
 +                    }
 +                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
 +                        let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
 +                        // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
 +                        // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
 +                        if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
 +                            needless_borrow_impl_arg_position(
 +                                cx,
 +                                possible_borrowers,
 +                                parent,
 +                                i + 1,
 +                                *param_ty,
 +                                e,
 +                                precedence,
 +                                msrv,
 +                            )
 +                        } else {
 +                            ty_auto_deref_stability(
 +                                cx,
 +                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
 +                                precedence,
 +                            )
 +                            .position_for_arg()
 +                        }
 +                    })
 +                },
 +                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
 +                    name: name.name,
 +                    of_union: is_union(cx.typeck_results(), child),
 +                }),
 +                ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
 +                ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
 +                | ExprKind::Index(child, _)
 +                    if child.hir_id == e.hir_id =>
 +                {
 +                    Some(Position::Postfix)
 +                },
 +                _ if child_id == e.hir_id => {
 +                    precedence = parent.precedence().order();
 +                    None
 +                },
 +                _ => None,
 +            },
 +            _ => None,
 +        }
 +    })
 +    .unwrap_or(Position::Other(precedence));
 +    (position, adjustments)
 +}
 +
 +fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
 +    typeck
 +        .expr_ty_adjusted(path_expr)
 +        .ty_adt_def()
 +        .map_or(false, rustc_middle::ty::AdtDef::is_union)
 +}
 +
 +fn closure_result_position<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    closure: &'tcx Closure<'_>,
 +    ty: Ty<'tcx>,
 +    precedence: i8,
 +) -> Position {
 +    match closure.fn_decl.output {
 +        FnRetTy::Return(hir_ty) => {
 +            if let Some(sig) = ty_sig(cx, ty)
 +                && let Some(output) = sig.output()
 +            {
 +                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
 +            } else {
 +                Position::Other(precedence)
 +            }
 +        },
 +        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
 +    }
 +}
 +
 +// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
 +//
 +// e.g.
 +// let x = Box::new(Box::new(0u32));
 +// let y1: &Box<_> = x.deref();
 +// let y2: &Box<_> = &x;
 +//
 +// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
 +// switching to auto-dereferencing.
 +fn binding_ty_auto_deref_stability<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: &'tcx hir::Ty<'_>,
 +    precedence: i8,
 +    binder_args: &'tcx List<BoundVariableKind>,
 +) -> Position {
 +    let TyKind::Rptr(_, ty) = &ty.kind else {
 +        return Position::Other(precedence);
 +    };
 +    let mut ty = ty;
 +
 +    loop {
 +        break match ty.ty.kind {
 +            TyKind::Rptr(_, ref ref_ty) => {
 +                ty = ref_ty;
 +                continue;
 +            },
 +            TyKind::Path(
 +                QPath::TypeRelative(_, path)
 +                | QPath::Resolved(
 +                    _,
 +                    Path {
 +                        segments: [.., path], ..
 +                    },
 +                ),
 +            ) => {
 +                if let Some(args) = path.args
 +                    && args.args.iter().any(|arg| match arg {
 +                        GenericArg::Infer(_) => true,
 +                        GenericArg::Type(ty) => ty_contains_infer(ty),
 +                        _ => false,
 +                    })
 +                {
 +                    Position::ReborrowStable(precedence)
 +                } else {
 +                    Position::DerefStable(
 +                        precedence,
 +                        cx.tcx
 +                            .erase_late_bound_regions(Binder::bind_with_vars(
 +                                cx.typeck_results().node_type(ty.ty.hir_id),
 +                                binder_args,
 +                            ))
 +                            .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
 +                    )
 +                }
 +            },
 +            TyKind::Slice(_) => Position::DerefStable(precedence, false),
 +            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
 +            TyKind::Never
 +            | TyKind::Tup(_)
 +            | TyKind::Path(_) => Position::DerefStable(
 +                precedence,
 +                cx.tcx
 +                    .erase_late_bound_regions(Binder::bind_with_vars(
 +                        cx.typeck_results().node_type(ty.ty.hir_id),
 +                        binder_args,
 +                    ))
 +                    .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
 +            ),
 +            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
 +                Position::ReborrowStable(precedence)
 +            },
 +        };
 +    }
 +}
 +
 +// Checks whether a type is inferred at some point.
 +// e.g. `_`, `Box<_>`, `[_]`
 +fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
 +    struct V(bool);
 +    impl Visitor<'_> for V {
 +        fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
 +            if self.0
 +                || matches!(
 +                    ty.kind,
 +                    TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err
 +                )
 +            {
 +                self.0 = true;
 +            } else {
 +                walk_ty(self, ty);
 +            }
 +        }
 +
 +        fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
 +            if self.0 || matches!(arg, GenericArg::Infer(_)) {
 +                self.0 = true;
 +            } else if let GenericArg::Type(ty) = arg {
 +                self.visit_ty(ty);
 +            }
 +        }
 +    }
 +    let mut v = V(false);
 +    v.visit_ty(ty);
 +    v.0
 +}
 +
 +fn call_is_qualified(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Path(path) = &expr.kind {
 +        match path {
 +            QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
 +            QPath::TypeRelative(_, segment) => segment.args.is_some(),
 +            QPath::LangItem(..) => false,
 +        }
 +    } else {
 +        false
 +    }
 +}
 +
 +// Checks whether:
 +// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
 +// * `e`'s type implements `Trait` and is copyable
 +// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
 +//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
 +// be moved, but it cannot be.
 +#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
 +fn needless_borrow_impl_arg_position<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 +    parent: &Expr<'tcx>,
 +    arg_index: usize,
 +    param_ty: ParamTy,
 +    mut expr: &Expr<'tcx>,
 +    precedence: i8,
 +    msrv: &Msrv,
 +) -> Position {
 +    let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
 +    let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
 +
 +    let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
 +    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
 +    let substs_with_expr_ty = cx
 +        .typeck_results()
 +        .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
 +            callee.hir_id
 +        } else {
 +            parent.hir_id
 +        });
 +
 +    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
 +    let projection_predicates = predicates
 +        .iter()
 +        .filter_map(|predicate| {
 +            if let PredicateKind::Clause(Clause::Projection(projection_predicate)) = predicate.kind().skip_binder() {
 +                Some(projection_predicate)
 +            } else {
 +                None
 +            }
 +        })
 +        .collect::<Vec<_>>();
 +
 +    let mut trait_with_ref_mut_self_method = false;
 +
 +    // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return.
 +    if predicates
 +        .iter()
 +        .filter_map(|predicate| {
 +            if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder()
 +                && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
 +            {
 +                Some(trait_predicate.trait_ref.def_id)
 +            } else {
 +                None
 +            }
 +        })
 +        .inspect(|trait_def_id| {
 +            trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id);
 +        })
 +        .all(|trait_def_id| {
 +            Some(trait_def_id) == destruct_trait_def_id
 +                || Some(trait_def_id) == sized_trait_def_id
 +                || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
 +        })
 +    {
 +        return Position::Other(precedence);
 +    }
 +
 +    // See:
 +    // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1289294201
 +    // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
 +    if projection_predicates
 +        .iter()
 +        .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
 +    {
 +        return Position::Other(precedence);
 +    }
 +
 +    // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
 +    // elements are modified each time `check_referent` is called.
 +    let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
 +
 +    let mut check_reference_and_referent = |reference, referent| {
 +        let referent_ty = cx.typeck_results().expr_ty(referent);
 +
 +        if !is_copy(cx, referent_ty)
 +            && (referent_ty.has_significant_drop(cx.tcx, cx.param_env)
 +                || !referent_used_exactly_once(cx, possible_borrowers, reference))
 +        {
 +            return false;
 +        }
 +
 +        // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
 +        if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
 +            return false;
 +        }
 +
 +        if !replace_types(
 +            cx,
 +            param_ty,
 +            referent_ty,
 +            fn_sig,
 +            arg_index,
 +            &projection_predicates,
 +            &mut substs_with_referent_ty,
 +        ) {
 +            return false;
 +        }
 +
 +        predicates.iter().all(|predicate| {
 +            if let PredicateKind::Clause(Clause::Trait(trait_predicate)) = predicate.kind().skip_binder()
 +                && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
 +                && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
 +                && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
 +                && ty.is_array()
 +                && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
 +            {
 +                return false;
 +            }
 +
 +            let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
 +            let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
 +            let infcx = cx.tcx.infer_ctxt().build();
 +            infcx.predicate_must_hold_modulo_regions(&obligation)
 +        })
 +    };
 +
 +    let mut needless_borrow = false;
 +    while let ExprKind::AddrOf(_, _, referent) = expr.kind {
 +        if !check_reference_and_referent(expr, referent) {
 +            break;
 +        }
 +        expr = referent;
 +        needless_borrow = true;
 +    }
 +
 +    if needless_borrow {
 +        Position::ImplArg(expr.hir_id)
 +    } else {
 +        Position::Other(precedence)
 +    }
 +}
 +
 +fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
 +    cx.tcx
 +        .associated_items(trait_def_id)
 +        .in_definition_order()
 +        .any(|assoc_item| {
 +            if assoc_item.fn_has_self_parameter {
 +                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
 +                matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
 +            } else {
 +                false
 +            }
 +        })
 +}
 +
 +fn is_mixed_projection_predicate<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    callee_def_id: DefId,
 +    projection_predicate: &ProjectionPredicate<'tcx>,
 +) -> bool {
 +    let generics = cx.tcx.generics_of(callee_def_id);
 +    // The predicate requires the projected type to equal a type parameter from the parent context.
 +    if let Some(term_ty) = projection_predicate.term.ty()
 +        && let ty::Param(term_param_ty) = term_ty.kind()
 +        && (term_param_ty.index as usize) < generics.parent_count
 +    {
 +        // The inner-most self type is a type parameter from the current function.
 +        let mut projection_ty = projection_predicate.projection_ty;
 +        loop {
 +            match projection_ty.self_ty().kind() {
 +                ty::Alias(ty::Projection, inner_projection_ty) => {
 +                    projection_ty = *inner_projection_ty;
 +                }
 +                ty::Param(param_ty) => {
 +                    return (param_ty.index as usize) >= generics.parent_count;
 +                }
 +                _ => {
 +                    return false;
 +                }
 +            }
 +        }
 +    } else {
 +        false
 +    }
 +}
 +
 +fn referent_used_exactly_once<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
 +    reference: &Expr<'tcx>,
 +) -> bool {
 +    let mir = enclosing_mir(cx.tcx, reference.hir_id);
 +    if let Some(local) = expr_local(cx.tcx, reference)
 +        && let [location] = *local_assignments(mir, local).as_slice()
 +        && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
 +        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
 +        && !place.has_deref()
 +        // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
 +        && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
 +    {
 +        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
 +        if possible_borrowers
 +            .last()
 +            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
 +        {
 +            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
 +        }
 +        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
 +        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
 +        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
 +        // itself. See the comment in that method for an explanation as to why.
 +        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
 +            && used_exactly_once(mir, place.local).unwrap_or(false)
 +    } else {
 +        false
 +    }
 +}
 +
 +// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
 +// projected type that is a type parameter. Returns `false` if replacing the types would have an
 +// effect on the function signature beyond substituting `new_ty` for `param_ty`.
 +// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
 +fn replace_types<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    param_ty: ParamTy,
 +    new_ty: Ty<'tcx>,
 +    fn_sig: FnSig<'tcx>,
 +    arg_index: usize,
 +    projection_predicates: &[ProjectionPredicate<'tcx>],
 +    substs: &mut [ty::GenericArg<'tcx>],
 +) -> bool {
 +    let mut replaced = BitSet::new_empty(substs.len());
 +
 +    let mut deque = VecDeque::with_capacity(substs.len());
 +    deque.push_back((param_ty, new_ty));
 +
 +    while let Some((param_ty, new_ty)) = deque.pop_front() {
 +        // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in.
 +        if !fn_sig
 +            .inputs_and_output
 +            .iter()
 +            .enumerate()
 +            .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx)))
 +        {
 +            return false;
 +        }
 +
 +        substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
 +
 +        // The `replaced.insert(...)` check provides some protection against infinite loops.
 +        if replaced.insert(param_ty.index) {
 +            for projection_predicate in projection_predicates {
 +                if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
 +                    && let Some(term_ty) = projection_predicate.term.ty()
 +                    && let ty::Param(term_param_ty) = term_ty.kind()
 +                {
 +                    let item_def_id = projection_predicate.projection_ty.def_id;
 +                    let assoc_item = cx.tcx.associated_item(item_def_id);
 +                    let projection = cx.tcx
 +                        .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
 +
 +                    if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
 +                        && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
 +                    {
 +                        deque.push_back((*term_param_ty, projected_ty));
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    true
 +}
 +
 +struct TyPosition<'tcx> {
 +    position: Position,
 +    ty: Option<Ty<'tcx>>,
 +}
 +impl From<Position> for TyPosition<'_> {
 +    fn from(position: Position) -> Self {
 +        Self { position, ty: None }
 +    }
 +}
 +impl<'tcx> TyPosition<'tcx> {
 +    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
 +        Self {
 +            position: Position::ReborrowStable(precedence),
 +            ty: Some(ty),
 +        }
 +    }
 +    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
 +        match (self.position, self.ty) {
 +            (Position::ReborrowStable(precedence), Some(ty)) => {
 +                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
 +            },
 +            (position, _) => position,
 +        }
 +    }
 +    fn position_for_arg(self) -> Position {
 +        self.position
 +    }
 +}
 +
 +// Checks whether a type is stable when switching to auto dereferencing,
 +fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
 +    let ty::Ref(_, mut ty, _) = *ty.kind() else {
 +        return Position::Other(precedence).into();
 +    };
 +
 +    loop {
 +        break match *ty.kind() {
 +            ty::Ref(_, ref_ty, _) => {
 +                ty = ref_ty;
 +                continue;
 +            },
 +            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
++            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
++                TyPosition::new_deref_stable_for_result(precedence, ty)
 +            },
++            ty::Infer(_)
++            | ty::Error(_)
++            | ty::Bound(..)
++            | ty::Alias(ty::Opaque, ..)
++            | ty::Placeholder(_)
++            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
 +            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
 +                Position::ReborrowStable(precedence).into()
 +            },
 +            ty::Adt(_, substs) if substs.has_non_region_param() => {
 +                TyPosition::new_deref_stable_for_result(precedence, ty)
 +            },
 +            ty::Bool
 +            | ty::Char
 +            | ty::Int(_)
 +            | ty::Uint(_)
 +            | ty::Array(..)
 +            | ty::Float(_)
 +            | ty::RawPtr(..)
 +            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
 +            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
 +            ty::Adt(..)
 +            | ty::Foreign(_)
 +            | ty::FnDef(..)
 +            | ty::Generator(..)
 +            | ty::GeneratorWitness(..)
 +            | ty::Closure(..)
 +            | ty::Never
 +            | ty::Tuple(_)
 +            | ty::Alias(ty::Projection, _) => {
 +                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
 +            },
 +        };
 +    }
 +}
 +
 +fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
 +    if let ty::Adt(adt, _) = *ty.kind() {
 +        adt.is_struct() && adt.all_fields().any(|f| f.name == name)
 +    } else {
 +        false
 +    }
 +}
 +
 +#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
 +fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
 +    match state {
 +        State::DerefMethod {
 +            ty_changed_count,
 +            is_final_ufcs,
 +            target_mut,
 +        } => {
 +            let mut app = Applicability::MachineApplicable;
 +            let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
 +            let ty = cx.typeck_results().expr_ty(expr);
 +            let (_, ref_count) = peel_mid_ty_refs(ty);
 +            let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
 +                // a deref call changing &T -> &U requires two deref operators the first time
 +                // this occurs. One to remove the reference, a second to call the deref impl.
 +                "*".repeat(ty_changed_count + 1)
 +            } else {
 +                "*".repeat(ty_changed_count)
 +            };
 +            let addr_of_str = if ty_changed_count < ref_count {
 +                // Check if a reborrow from &mut T -> &T is required.
 +                if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
 +                    "&*"
 +                } else {
 +                    ""
 +                }
 +            } else if target_mut == Mutability::Mut {
 +                "&mut "
 +            } else {
 +                "&"
 +            };
 +
 +            let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
 +                format!("({expr_str})")
 +            } else {
 +                expr_str.into_owned()
 +            };
 +
 +            span_lint_and_sugg(
 +                cx,
 +                EXPLICIT_DEREF_METHODS,
 +                data.span,
 +                match target_mut {
 +                    Mutability::Not => "explicit `deref` method call",
 +                    Mutability::Mut => "explicit `deref_mut` method call",
 +                },
 +                "try this",
 +                format!("{addr_of_str}{deref_str}{expr_str}"),
 +                app,
 +            );
 +        },
 +        State::DerefedBorrow(state) => {
 +            let mut app = Applicability::MachineApplicable;
 +            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
 +            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
 +            span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
 +                let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
 +                let sugg = if !snip_is_macro
 +                    && !has_enclosing_paren(&snip)
 +                    && (expr.precedence().order() < data.position.precedence() || calls_field)
 +                {
 +                    format!("({snip})")
 +                } else {
 +                    snip.into()
 +                };
 +                diag.span_suggestion(data.span, "change this to", sugg, app);
 +            });
 +        },
 +        State::ExplicitDeref { mutability } => {
 +            if matches!(
 +                expr.kind,
 +                ExprKind::Block(..)
 +                    | ExprKind::ConstBlock(_)
 +                    | ExprKind::If(..)
 +                    | ExprKind::Loop(..)
 +                    | ExprKind::Match(..)
 +            ) && matches!(data.position, Position::DerefStable(_, true))
 +            {
 +                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
 +                return;
 +            }
 +
 +            let (prefix, precedence) = if let Some(mutability) = mutability
 +                && !cx.typeck_results().expr_ty(expr).is_ref()
 +            {
 +                let prefix = match mutability {
 +                    Mutability::Not => "&",
 +                    Mutability::Mut => "&mut ",
 +                };
 +                (prefix, 0)
 +            } else {
 +                ("", data.position.precedence())
 +            };
 +            span_lint_hir_and_then(
 +                cx,
 +                EXPLICIT_AUTO_DEREF,
 +                data.hir_id,
 +                data.span,
 +                "deref which would be done by auto-deref",
 +                |diag| {
 +                    let mut app = Applicability::MachineApplicable;
 +                    let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
 +                    let sugg =
 +                        if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
 +                            format!("{prefix}({snip})")
 +                        } else {
 +                            format!("{prefix}{snip}")
 +                        };
 +                    diag.span_suggestion(data.span, "try this", sugg, app);
 +                },
 +            );
 +        },
 +        State::ExplicitDerefField { .. } => {
 +            if matches!(
 +                expr.kind,
 +                ExprKind::Block(..)
 +                    | ExprKind::ConstBlock(_)
 +                    | ExprKind::If(..)
 +                    | ExprKind::Loop(..)
 +                    | ExprKind::Match(..)
 +            ) && matches!(data.position, Position::DerefStable(_, true))
 +            {
 +                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
 +                return;
 +            }
 +
 +            span_lint_hir_and_then(
 +                cx,
 +                EXPLICIT_AUTO_DEREF,
 +                data.hir_id,
 +                data.span,
 +                "deref which would be done by auto-deref",
 +                |diag| {
 +                    let mut app = Applicability::MachineApplicable;
 +                    let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
 +                    diag.span_suggestion(data.span, "try this", snip.into_owned(), app);
 +                },
 +            );
 +        },
 +        State::Borrow { .. } | State::Reborrow { .. } => (),
 +    }
 +}
 +
 +impl<'tcx> Dereferencing<'tcx> {
 +    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
 +        if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
 +            if let Some(pat) = outer_pat {
 +                // Check for auto-deref
 +                if !matches!(
 +                    cx.typeck_results().expr_adjustments(e),
 +                    [
 +                        Adjustment {
 +                            kind: Adjust::Deref(_),
 +                            ..
 +                        },
 +                        Adjustment {
 +                            kind: Adjust::Deref(_),
 +                            ..
 +                        },
 +                        ..
 +                    ]
 +                ) {
 +                    match get_parent_expr(cx, e) {
 +                        // Field accesses are the same no matter the number of references.
 +                        Some(Expr {
 +                            kind: ExprKind::Field(..),
 +                            ..
 +                        }) => (),
 +                        Some(&Expr {
 +                            span,
 +                            kind: ExprKind::Unary(UnOp::Deref, _),
 +                            ..
 +                        }) if !span.from_expansion() => {
 +                            // Remove explicit deref.
 +                            let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
 +                            pat.replacements.push((span, snip.into()));
 +                        },
 +                        Some(parent) if !parent.span.from_expansion() => {
 +                            // Double reference might be needed at this point.
 +                            if parent.precedence().order() == PREC_POSTFIX {
 +                                // Parentheses would be needed here, don't lint.
 +                                *outer_pat = None;
 +                            } else {
 +                                pat.always_deref = false;
 +                                let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
 +                                pat.replacements.push((e.span, format!("&{snip}")));
 +                            }
 +                        },
 +                        _ if !e.span.from_expansion() => {
 +                            // Double reference might be needed at this point.
 +                            pat.always_deref = false;
 +                            let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
 +                            pat.replacements.push((e.span, format!("&{snip}")));
 +                        },
 +                        // Edge case for macros. The span of the identifier will usually match the context of the
 +                        // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
 +                        // macros
 +                        _ => *outer_pat = None,
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
index 3f0b165f2b604a006e253bf4972c458611599212,0000000000000000000000000000000000000000..cf3483d4c00b17134724bbc51eafcf6abb904aaa
mode 100644,000000..100644
--- /dev/null
@@@ -1,528 -1,0 +1,525 @@@
-                     trait_ref: tcx.mk_trait_ref(
-                         eq_trait_id,
-                         [tcx.mk_param_from_def(param)],
-                     ),
 +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::paths;
 +use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 +use clippy_utils::{is_lint_allowed, match_def_path};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 +use rustc_hir::{
 +    self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource,
 +    Unsafety,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::nested_filter;
 +use rustc_middle::traits::Reveal;
 +use rustc_middle::ty::{
 +    self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
 +    Ty, TyCtxt,
 +};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `Hash` but implementing `PartialEq`
 +    /// explicitly or vice versa.
 +    ///
 +    /// ### Why is this bad?
 +    /// The implementation of these traits must agree (for
 +    /// example for use with `HashMap`) so it’s probably a bad idea to use a
 +    /// default-generated `Hash` implementation with an explicitly defined
 +    /// `PartialEq`. In particular, the following must hold for any type:
 +    ///
 +    /// ```text
 +    /// k1 == k2 ⇒ hash(k1) == hash(k2)
 +    /// ```
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// #[derive(Hash)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialEq for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DERIVE_HASH_XOR_EQ,
 +    correctness,
 +    "deriving `Hash` but implementing `PartialEq` explicitly"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `Ord` but implementing `PartialOrd`
 +    /// explicitly or vice versa.
 +    ///
 +    /// ### Why is this bad?
 +    /// The implementation of these traits must agree (for
 +    /// example for use with `sort`) so it’s probably a bad idea to use a
 +    /// default-generated `Ord` implementation with an explicitly defined
 +    /// `PartialOrd`. In particular, the following must hold for any type
 +    /// implementing `Ord`:
 +    ///
 +    /// ```text
 +    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
 +    /// ```
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// #[derive(Ord, PartialEq, Eq)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialOrd for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// #[derive(PartialEq, Eq)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialOrd for Foo {
 +    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
 +    ///        Some(self.cmp(other))
 +    ///     }
 +    /// }
 +    ///
 +    /// impl Ord for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    /// or, if you don't need a custom ordering:
 +    /// ```rust,ignore
 +    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
 +    /// struct Foo;
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub DERIVE_ORD_XOR_PARTIAL_ORD,
 +    correctness,
 +    "deriving `Ord` but implementing `PartialOrd` explicitly"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for explicit `Clone` implementations for `Copy`
 +    /// types.
 +    ///
 +    /// ### Why is this bad?
 +    /// To avoid surprising behavior, these traits should
 +    /// agree and the behavior of `Copy` cannot be overridden. In almost all
 +    /// situations a `Copy` type should have a `Clone` implementation that does
 +    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
 +    /// gets you.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// #[derive(Copy)]
 +    /// struct Foo;
 +    ///
 +    /// impl Clone for Foo {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EXPL_IMPL_CLONE_ON_COPY,
 +    pedantic,
 +    "implementing `Clone` explicitly on `Copy` types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `serde::Deserialize` on a type that
 +    /// has methods using `unsafe`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Deriving `serde::Deserialize` will create a constructor
 +    /// that may violate invariants hold by another constructor.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// use serde::Deserialize;
 +    ///
 +    /// #[derive(Deserialize)]
 +    /// pub struct Foo {
 +    ///     // ..
 +    /// }
 +    ///
 +    /// impl Foo {
 +    ///     pub fn new() -> Self {
 +    ///         // setup here ..
 +    ///     }
 +    ///
 +    ///     pub unsafe fn parts() -> (&str, &str) {
 +    ///         // assumes invariants hold
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub UNSAFE_DERIVE_DESERIALIZE,
 +    pedantic,
 +    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for types that derive `PartialEq` and could implement `Eq`.
 +    ///
 +    /// ### Why is this bad?
 +    /// If a type `T` derives `PartialEq` and all of its members implement `Eq`,
 +    /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
 +    /// in APIs that require `Eq` types. It also allows structs containing `T` to derive
 +    /// `Eq` themselves.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// #[derive(PartialEq)]
 +    /// struct Foo {
 +    ///     i_am_eq: i32,
 +    ///     i_am_eq_too: Vec<String>,
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// #[derive(PartialEq, Eq)]
 +    /// struct Foo {
 +    ///     i_am_eq: i32,
 +    ///     i_am_eq_too: Vec<String>,
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.63.0"]
 +    pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
 +    nursery,
 +    "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
 +}
 +
 +declare_lint_pass!(Derive => [
 +    EXPL_IMPL_CLONE_ON_COPY,
 +    DERIVE_HASH_XOR_EQ,
 +    DERIVE_ORD_XOR_PARTIAL_ORD,
 +    UNSAFE_DERIVE_DESERIALIZE,
 +    DERIVE_PARTIAL_EQ_WITHOUT_EQ
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Derive {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Impl(Impl {
 +            of_trait: Some(ref trait_ref),
 +            ..
 +        }) = item.kind
 +        {
 +            let ty = cx.tcx.type_of(item.owner_id);
 +            let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
 +
 +            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
 +            check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
 +
 +            if is_automatically_derived {
 +                check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
 +                check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
 +            } else {
 +                check_copy_clone(cx, item, trait_ref, ty);
 +            }
 +        }
 +    }
 +}
 +
 +/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
 +fn check_hash_peq<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    trait_ref: &hir::TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +    hash_is_automatically_derived: bool,
 +) {
 +    if_chain! {
 +        if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
 +        if let Some(def_id) = trait_ref.trait_def_id();
 +        if cx.tcx.is_diagnostic_item(sym::Hash, def_id);
 +        then {
 +            // Look for the PartialEq implementations for `ty`
 +            cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
 +                let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
 +
 +                if peq_is_automatically_derived == hash_is_automatically_derived {
 +                    return;
 +                }
 +
 +                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
 +
 +                // Only care about `impl PartialEq<Foo> for Foo`
 +                // For `impl PartialEq<B> for A, input_types is [A, B]
 +                if trait_ref.substs.type_at(1) == ty {
 +                    let mess = if peq_is_automatically_derived {
 +                        "you are implementing `Hash` explicitly but have derived `PartialEq`"
 +                    } else {
 +                        "you are deriving `Hash` but have implemented `PartialEq` explicitly"
 +                    };
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        DERIVE_HASH_XOR_EQ,
 +                        span,
 +                        mess,
 +                        |diag| {
 +                            if let Some(local_def_id) = impl_id.as_local() {
 +                                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +                                diag.span_note(
 +                                    cx.tcx.hir().span(hir_id),
 +                                    "`PartialEq` implemented here"
 +                                );
 +                            }
 +                        }
 +                    );
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
 +fn check_ord_partial_ord<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    trait_ref: &hir::TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +    ord_is_automatically_derived: bool,
 +) {
 +    if_chain! {
 +        if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord);
 +        if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait();
 +        if let Some(def_id) = &trait_ref.trait_def_id();
 +        if *def_id == ord_trait_def_id;
 +        then {
 +            // Look for the PartialOrd implementations for `ty`
 +            cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
 +                let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
 +
 +                if partial_ord_is_automatically_derived == ord_is_automatically_derived {
 +                    return;
 +                }
 +
 +                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
 +
 +                // Only care about `impl PartialOrd<Foo> for Foo`
 +                // For `impl PartialOrd<B> for A, input_types is [A, B]
 +                if trait_ref.substs.type_at(1) == ty {
 +                    let mess = if partial_ord_is_automatically_derived {
 +                        "you are implementing `Ord` explicitly but have derived `PartialOrd`"
 +                    } else {
 +                        "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
 +                    };
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        DERIVE_ORD_XOR_PARTIAL_ORD,
 +                        span,
 +                        mess,
 +                        |diag| {
 +                            if let Some(local_def_id) = impl_id.as_local() {
 +                                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +                                diag.span_note(
 +                                    cx.tcx.hir().span(hir_id),
 +                                    "`PartialOrd` implemented here"
 +                                );
 +                            }
 +                        }
 +                    );
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
 +fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
 +    let clone_id = match cx.tcx.lang_items().clone_trait() {
 +        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
 +        _ => return,
 +    };
 +    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return };
 +    let (ty_adt, ty_subs) = match *ty.kind() {
 +        // Unions can't derive clone.
 +        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
 +        _ => return,
 +    };
 +    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
 +    // there's a Copy impl for any instance of the adt.
 +    if !is_copy(cx, ty) {
 +        if ty_subs.non_erasable_generics().next().is_some() {
 +            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
 +                impls
 +                    .iter()
 +                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
 +            });
 +            if !has_copy_impl {
 +                return;
 +            }
 +        } else {
 +            return;
 +        }
 +    }
 +    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
 +    // this impl.
 +    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
 +        return;
 +    }
 +
 +    span_lint_and_note(
 +        cx,
 +        EXPL_IMPL_CLONE_ON_COPY,
 +        item.span,
 +        "you are implementing `Clone` explicitly on a `Copy` type",
 +        Some(item.span),
 +        "consider deriving `Clone` or removing `Copy`",
 +    );
 +}
 +
 +/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
 +fn check_unsafe_derive_deserialize<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    item: &Item<'_>,
 +    trait_ref: &hir::TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +) {
 +    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
 +        let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
 +        walk_item(&mut visitor, item);
 +        visitor.has_unsafe
 +    }
 +
 +    if_chain! {
 +        if let Some(trait_def_id) = trait_ref.trait_def_id();
 +        if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE);
 +        if let ty::Adt(def, _) = ty.kind();
 +        if let Some(local_def_id) = def.did().as_local();
 +        let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +        if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
 +        if cx.tcx.inherent_impls(def.did())
 +            .iter()
 +            .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
 +            .any(|imp| has_unsafe(cx, imp));
 +        then {
 +            span_lint_and_help(
 +                cx,
 +                UNSAFE_DERIVE_DESERIALIZE,
 +                item.span,
 +                "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
 +                None,
 +                "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html"
 +            );
 +        }
 +    }
 +}
 +
 +struct UnsafeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    has_unsafe: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 +    type NestedFilter = nested_filter::All;
 +
 +    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) {
 +        if self.has_unsafe {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let Some(header) = kind.header();
 +            if header.unsafety == Unsafety::Unsafe;
 +            then {
 +                self.has_unsafe = true;
 +            }
 +        }
 +
 +        walk_fn(self, kind, decl, body_id, id);
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.has_unsafe {
 +            return;
 +        }
 +
 +        if let ExprKind::Block(block, _) = expr.kind {
 +            if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
 +                self.has_unsafe = true;
 +            }
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +}
 +
 +/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
 +fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
 +    if_chain! {
 +        if let ty::Adt(adt, substs) = ty.kind();
 +        if cx.tcx.visibility(adt.did()).is_public();
 +        if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
 +        if let Some(def_id) = trait_ref.trait_def_id();
 +        if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
 +        let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
 +        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []);
 +        // If all of our fields implement `Eq`, we can implement `Eq` too
 +        if adt
 +            .all_fields()
 +            .map(|f| f.ty(cx.tcx, substs))
 +            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                DERIVE_PARTIAL_EQ_WITHOUT_EQ,
 +                span.ctxt().outer_expn_data().call_site,
 +                "you are deriving `PartialEq` and can implement `Eq`",
 +                "consider deriving `Eq` as well",
 +                "PartialEq, Eq".to_string(),
 +                Applicability::MachineApplicable,
 +            )
 +        }
 +    }
 +}
 +
 +/// Creates the `ParamEnv` used for the give type's derived `Eq` impl.
 +fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> {
 +    // Initial map from generic index to param def.
 +    // Vec<(param_def, needs_eq)>
 +    let mut params = tcx
 +        .generics_of(did)
 +        .params
 +        .iter()
 +        .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
 +        .collect::<Vec<_>>();
 +
 +    let ty_predicates = tcx.predicates_of(did).predicates;
 +    for (p, _) in ty_predicates {
 +        if let PredicateKind::Clause(Clause::Trait(p)) = p.kind().skip_binder()
 +            && p.trait_ref.def_id == eq_trait_id
 +            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
 +            && p.constness == BoundConstness::NotConst
 +        {
 +            // Flag types which already have an `Eq` bound.
 +            params[self_ty.index as usize].1 = false;
 +        }
 +    }
 +
 +    ParamEnv::new(
 +        tcx.mk_predicates(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)]),
 +                    constness: BoundConstness::NotConst,
 +                    polarity: ImplPolarity::Positive,
 +                }))))
 +            }),
 +        )),
 +        Reveal::UserFacing,
 +        Constness::NotConst,
 +    )
 +}
index 68122b4cef577fede678085f08f58baa9181cbe1,0000000000000000000000000000000000000000..1971cab64ef38a8f01890c1cd8394f7bd238af96
mode 100644,000000..100644
--- /dev/null
@@@ -1,150 -1,0 +1,150 @@@
-     #[clippy::version = "1.65.0"]
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::macros::macro_backtrace;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_hir::def_id::DefIdMap;
 +use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{ExpnId, Span};
 +
 +use crate::utils::conf;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Denies the configured macros in clippy.toml
 +    ///
 +    /// Note: Even though this lint is warn-by-default, it will only trigger if
 +    /// macros are defined in the clippy.toml file.
 +    ///
 +    /// ### Why is this bad?
 +    /// Some macros are undesirable in certain contexts, and it's beneficial to
 +    /// lint for them as needed.
 +    ///
 +    /// ### Example
 +    /// An example clippy.toml configuration:
 +    /// ```toml
 +    /// # clippy.toml
 +    /// disallowed-macros = [
 +    ///     # Can use a string as the path of the disallowed macro.
 +    ///     "std::print",
 +    ///     # Can also use an inline table with a `path` key.
 +    ///     { path = "std::println" },
 +    ///     # When using an inline table, can add a `reason` for why the macro
 +    ///     # is disallowed.
 +    ///     { path = "serde::Serialize", reason = "no serializing" },
 +    /// ]
 +    /// ```
 +    /// ```
 +    /// use serde::Serialize;
 +    ///
 +    /// // Example code where clippy issues a warning
 +    /// println!("warns");
 +    ///
 +    /// // The diagnostic will contain the message "no serializing"
 +    /// #[derive(Serialize)]
 +    /// struct Data {
 +    ///     name: String,
 +    ///     value: usize,
 +    /// }
 +    /// ```
++    #[clippy::version = "1.66.0"]
 +    pub DISALLOWED_MACROS,
 +    style,
 +    "use of a disallowed macro"
 +}
 +
 +pub struct DisallowedMacros {
 +    conf_disallowed: Vec<conf::DisallowedPath>,
 +    disallowed: DefIdMap<usize>,
 +    seen: FxHashSet<ExpnId>,
 +}
 +
 +impl DisallowedMacros {
 +    pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
 +        Self {
 +            conf_disallowed,
 +            disallowed: DefIdMap::default(),
 +            seen: FxHashSet::default(),
 +        }
 +    }
 +
 +    fn check(&mut self, cx: &LateContext<'_>, span: Span) {
 +        if self.conf_disallowed.is_empty() {
 +            return;
 +        }
 +
 +        for mac in macro_backtrace(span) {
 +            if !self.seen.insert(mac.expn) {
 +                return;
 +            }
 +
 +            if let Some(&index) = self.disallowed.get(&mac.def_id) {
 +                let conf = &self.conf_disallowed[index];
 +
 +                span_lint_and_then(
 +                    cx,
 +                    DISALLOWED_MACROS,
 +                    mac.span,
 +                    &format!("use of a disallowed macro `{}`", conf.path()),
 +                    |diag| {
 +                        if let Some(reason) = conf.reason() {
 +                            diag.note(reason);
 +                        }
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
 +
 +impl LateLintPass<'_> for DisallowedMacros {
 +    fn check_crate(&mut self, cx: &LateContext<'_>) {
 +        for (index, conf) in self.conf_disallowed.iter().enumerate() {
 +            let segs: Vec<_> = conf.path().split("::").collect();
 +            for id in clippy_utils::def_path_def_ids(cx, &segs) {
 +                self.disallowed.insert(id, index);
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        self.check(cx, expr.span);
 +    }
 +
 +    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
 +        self.check(cx, stmt.span);
 +    }
 +
 +    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
 +        self.check(cx, ty.span);
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
 +        self.check(cx, pat.span);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        self.check(cx, item.span);
 +        self.check(cx, item.vis_span);
 +    }
 +
 +    fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) {
 +        self.check(cx, item.span);
 +        self.check(cx, item.vis_span);
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
 +        self.check(cx, item.span);
 +        self.check(cx, item.vis_span);
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
 +        self.check(cx, item.span);
 +    }
 +
 +    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
 +        self.check(cx, path.span);
 +    }
 +}
index 111b624f52994d747fc327b41830a4cbbba11ff8,0000000000000000000000000000000000000000..69f7c152fc4af84ad6eb70ce628129babe33502f
mode 100644,000000..100644
--- /dev/null
@@@ -1,461 -1,0 +1,463 @@@
-     is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::is_diag_trait_item;
 +use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
 +use clippy_utils::macros::{
-     #[clippy::version = "1.65.0"]
++    is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam,
++    FormatParamUsage,
 +};
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::source::snippet_opt;
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 +use if_chain::if_chain;
 +use itertools::Itertools;
 +use rustc_errors::{
 +    Applicability,
 +    SuggestionStyle::{CompletelyHidden, ShowCode},
 +};
 +use rustc_hir::{Expr, ExprKind, HirId, QPath};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 +use rustc_middle::ty::Ty;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::def_id::DefId;
 +use rustc_span::edition::Edition::Edition2021;
 +use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects `format!` within the arguments of another macro that does
 +    /// formatting such as `format!` itself, `write!` or `println!`. Suggests
 +    /// inlining the `format!` call.
 +    ///
 +    /// ### Why is this bad?
 +    /// The recommended code is both shorter and avoids a temporary allocation.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::panic::Location;
 +    /// println!("error: {}", format!("something failed at {}", Location::caller()));
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::panic::Location;
 +    /// println!("error: something failed at {}", Location::caller());
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub FORMAT_IN_FORMAT_ARGS,
 +    perf,
 +    "`format!` used in a macro that does formatting"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
 +    /// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
 +    /// in a macro that does formatting.
 +    ///
 +    /// ### Why is this bad?
 +    /// Since the type implements `Display`, the use of `to_string` is
 +    /// unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::panic::Location;
 +    /// println!("error: something failed at {}", Location::caller().to_string());
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::panic::Location;
 +    /// println!("error: something failed at {}", Location::caller());
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub TO_STRING_IN_FORMAT_ARGS,
 +    perf,
 +    "`to_string` applied to a type that implements `Display` in format args"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detect when a variable is not inlined in a format string,
 +    /// and suggests to inline it.
 +    ///
 +    /// ### Why is this bad?
 +    /// Non-inlined code is slightly more difficult to read and understand,
 +    /// as it requires arguments to be matched against the format string.
 +    /// The inlined syntax, where allowed, is simpler.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let var = 42;
 +    /// # let width = 1;
 +    /// # let prec = 2;
 +    /// format!("{}", var);
 +    /// format!("{v:?}", v = var);
 +    /// format!("{0} {0}", var);
 +    /// format!("{0:1$}", var, width);
 +    /// format!("{:.*}", prec, var);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let var = 42;
 +    /// # let width = 1;
 +    /// # let prec = 2;
 +    /// format!("{var}");
 +    /// format!("{var:?}");
 +    /// format!("{var} {var}");
 +    /// format!("{var:width$}");
 +    /// format!("{var:.prec$}");
 +    /// ```
 +    ///
 +    /// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
 +    /// the following code will also trigger the lint:
 +    /// ```rust
 +    /// # let var = 42;
 +    /// format!("{} {}", var, 1+2);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let var = 42;
 +    /// format!("{var} {}", 1+2);
 +    /// ```
 +    ///
 +    /// ### Known Problems
 +    ///
 +    /// If a format string contains a numbered argument that cannot be inlined
 +    /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
-     if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
-         // panic! before 2021 edition considers a single string argument as non-format
++    #[clippy::version = "1.66.0"]
 +    pub UNINLINED_FORMAT_ARGS,
 +    style,
 +    "using non-inlined variables in `format!` calls"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects [formatting parameters] that have no effect on the output of
 +    /// `format!()`, `println!()` or similar macros.
 +    ///
 +    /// ### Why is this bad?
 +    /// Shorter format specifiers are easier to read, it may also indicate that
 +    /// an expected formatting operation such as adding padding isn't happening.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// println!("{:.}", 1.0);
 +    ///
 +    /// println!("not padded: {:5}", format_args!("..."));
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// println!("{}", 1.0);
 +    ///
 +    /// println!("not padded: {}", format_args!("..."));
 +    /// // OR
 +    /// println!("padded: {:5}", format!("..."));
 +    /// ```
 +    ///
 +    /// [formatting parameters]: https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters
 +    #[clippy::version = "1.66.0"]
 +    pub UNUSED_FORMAT_SPECS,
 +    complexity,
 +    "use of a format specifier that has no effect"
 +}
 +
 +impl_lint_pass!(FormatArgs => [
 +    FORMAT_IN_FORMAT_ARGS,
 +    TO_STRING_IN_FORMAT_ARGS,
 +    UNINLINED_FORMAT_ARGS,
 +    UNUSED_FORMAT_SPECS,
 +]);
 +
 +pub struct FormatArgs {
 +    msrv: Msrv,
 +    ignore_mixed: bool,
 +}
 +
 +impl FormatArgs {
 +    #[must_use]
 +    pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
 +        Self {
 +            msrv,
 +            ignore_mixed: allow_mixed_uninlined_format_args,
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for FormatArgs {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 +        if let Some(format_args) = FormatArgsExpn::parse(cx, expr)
 +            && let expr_expn_data = expr.span.ctxt().outer_expn_data()
 +            && let outermost_expn_data = outermost_expn_data(expr_expn_data)
 +            && let Some(macro_def_id) = outermost_expn_data.macro_def_id
 +            && is_format_macro(cx, macro_def_id)
 +            && let ExpnKind::Macro(_, name) = outermost_expn_data.kind
 +        {
 +            for arg in &format_args.args {
 +                check_unused_format_specifier(cx, arg);
 +                if !arg.format.is_default() {
 +                    continue;
 +                }
 +                if is_aliased(&format_args, arg.param.value.hir_id) {
 +                    continue;
 +                }
 +                check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
 +                check_to_string_in_format_args(cx, name, arg.param.value);
 +            }
 +            if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) {
 +                check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id, self.ignore_mixed);
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
 +    let param_ty = cx.typeck_results().expr_ty(arg.param.value).peel_refs();
 +
 +    if let Count::Implied(Some(mut span)) = arg.format.precision
 +        && !span.is_empty()
 +    {
 +        span_lint_and_then(
 +            cx,
 +            UNUSED_FORMAT_SPECS,
 +            span,
 +            "empty precision specifier has no effect",
 +            |diag| {
 +                if param_ty.is_floating_point() {
 +                    diag.note("a precision specifier is not required to format floats");
 +                }
 +
 +                if arg.format.is_default() {
 +                    // If there's no other specifiers remove the `:` too
 +                    span = arg.format_span();
 +                }
 +
 +                diag.span_suggestion_verbose(span, "remove the `.`", "", Applicability::MachineApplicable);
 +            },
 +        );
 +    }
 +
 +    if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
 +        span_lint_and_then(
 +            cx,
 +            UNUSED_FORMAT_SPECS,
 +            arg.span,
 +            "format specifiers have no effect on `format_args!()`",
 +            |diag| {
 +                let mut suggest_format = |spec, span| {
 +                    let message = format!("for the {spec} to apply consider using `format!()`");
 +
 +                    if let Some(mac_call) = root_macro_call(arg.param.value.span)
 +                        && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id)
 +                        && arg.span.eq_ctxt(mac_call.span)
 +                    {
 +                        diag.span_suggestion(
 +                            cx.sess().source_map().span_until_char(mac_call.span, '!'),
 +                            message,
 +                            "format",
 +                            Applicability::MaybeIncorrect,
 +                        );
 +                    } else if let Some(span) = span {
 +                        diag.span_help(span, message);
 +                    }
 +                };
 +
 +                if !arg.format.width.is_implied() {
 +                    suggest_format("width", arg.format.width.span());
 +                }
 +
 +                if !arg.format.precision.is_implied() {
 +                    suggest_format("precision", arg.format.precision.span());
 +                }
 +
 +                diag.span_suggestion_verbose(
 +                    arg.format_span(),
 +                    "if the current behavior is intentional, remove the format specifiers",
 +                    "",
 +                    Applicability::MaybeIncorrect,
 +                );
 +            },
 +        );
 +    }
 +}
 +
 +fn check_uninlined_args(
 +    cx: &LateContext<'_>,
 +    args: &FormatArgsExpn<'_>,
 +    call_site: Span,
 +    def_id: DefId,
 +    ignore_mixed: bool,
 +) {
 +    if args.format_string.span.from_expansion() {
 +        return;
 +    }
++    if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) {
++        // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as
++        // non-format
 +        return;
 +    }
 +
 +    let mut fixes = Vec::new();
 +    // If any of the arguments are referenced by an index number,
 +    // and that argument is not a simple variable and cannot be inlined,
 +    // we cannot remove any other arguments in the format string,
 +    // because the index numbers might be wrong after inlining.
 +    // Example of an un-inlinable format:  print!("{}{1}", foo, 2)
 +    if !args.params().all(|p| check_one_arg(args, &p, &mut fixes, ignore_mixed)) || fixes.is_empty() {
 +        return;
 +    }
 +
 +    // multiline span display suggestion is sometimes broken: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
 +    // in those cases, make the code suggestion hidden
 +    let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
 +
 +    span_lint_and_then(
 +        cx,
 +        UNINLINED_FORMAT_ARGS,
 +        call_site,
 +        "variables can be used directly in the `format!` string",
 +        |diag| {
 +            diag.multipart_suggestion_with_style(
 +                "change this to",
 +                fixes,
 +                Applicability::MachineApplicable,
 +                if multiline_fix { CompletelyHidden } else { ShowCode },
 +            );
 +        },
 +    );
 +}
 +
 +fn check_one_arg(
 +    args: &FormatArgsExpn<'_>,
 +    param: &FormatParam<'_>,
 +    fixes: &mut Vec<(Span, String)>,
 +    ignore_mixed: bool,
 +) -> bool {
 +    if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
 +        && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
 +        && let [segment] = path.segments
 +        && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
 +    {
 +        let replacement = match param.usage {
 +            FormatParamUsage::Argument => segment.ident.name.to_string(),
 +            FormatParamUsage::Width => format!("{}$", segment.ident.name),
 +            FormatParamUsage::Precision => format!(".{}$", segment.ident.name),
 +        };
 +        fixes.push((param.span, replacement));
 +        fixes.push((arg_span, String::new()));
 +        true  // successful inlining, continue checking
 +    } else {
 +        // Do not continue inlining (return false) in case
 +        // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)`
 +        // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already
 +        param.kind != Numbered && (!ignore_mixed || matches!(param.kind, NamedInline(_)))
 +    }
 +}
 +
 +fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
 +    if expn_data.call_site.from_expansion() {
 +        outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
 +    } else {
 +        expn_data
 +    }
 +}
 +
 +fn check_format_in_format_args(
 +    cx: &LateContext<'_>,
 +    call_site: Span,
 +    name: Symbol,
 +    arg: &Expr<'_>,
 +) {
 +    let expn_data = arg.span.ctxt().outer_expn_data();
 +    if expn_data.call_site.from_expansion() {
 +        return;
 +    }
 +    let Some(mac_id) = expn_data.macro_def_id else { return };
 +    if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) {
 +        return;
 +    }
 +    span_lint_and_then(
 +        cx,
 +        FORMAT_IN_FORMAT_ARGS,
 +        call_site,
 +        &format!("`format!` in `{name}!` args"),
 +        |diag| {
 +            diag.help(&format!(
 +                "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
 +            ));
 +            diag.help("or consider changing `format!` to `format_args!`");
 +        },
 +    );
 +}
 +
 +fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
 +    if_chain! {
 +        if !value.span.from_expansion();
 +        if let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind;
 +        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
 +        if is_diag_trait_item(cx, method_def_id, sym::ToString);
 +        let receiver_ty = cx.typeck_results().expr_ty(receiver);
 +        if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
 +        let (n_needed_derefs, target) =
 +            count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter());
 +        if implements_trait(cx, target, display_trait_id, &[]);
 +        if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait();
 +        if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
 +        then {
 +            let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
 +            if n_needed_derefs == 0 && !needs_ref {
 +                span_lint_and_sugg(
 +                    cx,
 +                    TO_STRING_IN_FORMAT_ARGS,
 +                    to_string_span.with_lo(receiver.span.hi()),
 +                    &format!(
 +                        "`to_string` applied to a type that implements `Display` in `{name}!` args"
 +                    ),
 +                    "remove this",
 +                    String::new(),
 +                    Applicability::MachineApplicable,
 +                );
 +            } else {
 +                span_lint_and_sugg(
 +                    cx,
 +                    TO_STRING_IN_FORMAT_ARGS,
 +                    value.span,
 +                    &format!(
 +                        "`to_string` applied to a type that implements `Display` in `{name}!` args"
 +                    ),
 +                    "use this",
 +                    format!(
 +                        "{}{:*>n_needed_derefs$}{receiver_snippet}",
 +                        if needs_ref { "&" } else { "" },
 +                        ""
 +                    ),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Returns true if `hir_id` is referred to by multiple format params
 +fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
 +    args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
 +}
 +
 +fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
 +where
 +    I: Iterator<Item = &'tcx Adjustment<'tcx>>,
 +{
 +    let mut n_total = 0;
 +    let mut n_needed = 0;
 +    loop {
 +        if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
 +            n_total += 1;
 +            if overloaded_deref.is_some() {
 +                n_needed = n_total;
 +            }
 +            ty = *target;
 +        } else {
 +            return (n_needed, ty);
 +        }
 +    }
 +}
index 0634b2798fefee63669f0a2325e9e89b8332ca7a,0000000000000000000000000000000000000000..a92f7548ff254d16a2f51b255675650d139e8734
mode 100644,000000..100644
--- /dev/null
@@@ -1,213 -1,0 +1,214 @@@
- use rustc_middle::hir::nested_filter::OnlyBodies;
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::macros::span_is_local;
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::path_def_id;
 +use clippy_utils::source::snippet_opt;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_path, Visitor};
 +use rustc_hir::{
 +    GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty,
 +    TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::{kw, sym};
 +use rustc_span::{Span, Symbol};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct StringWrapper(String);
 +    ///
 +    /// impl Into<StringWrapper> for String {
 +    ///     fn into(self) -> StringWrapper {
 +    ///         StringWrapper(self)
 +    ///     }
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// struct StringWrapper(String);
 +    ///
 +    /// impl From<String> for StringWrapper {
 +    ///     fn from(s: String) -> StringWrapper {
 +    ///         StringWrapper(s)
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub FROM_OVER_INTO,
 +    style,
 +    "Warns on implementations of `Into<..>` to use `From<..>`"
 +}
 +
 +pub struct FromOverInto {
 +    msrv: Msrv,
 +}
 +
 +impl FromOverInto {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        FromOverInto { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 +
 +impl<'tcx> LateLintPass<'tcx> for FromOverInto {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if !self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
 +            return;
 +        }
 +
 +        if let ItemKind::Impl(Impl {
 +            of_trait: Some(hir_trait_ref),
 +            self_ty,
 +            items: [impl_item_ref],
 +            ..
 +        }) = item.kind
 +            && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
 +            // `impl Into<target_ty> for self_ty`
 +            && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
 +            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
 +            && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
++            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
 +        {
 +            span_lint_and_then(
 +                cx,
 +                FROM_OVER_INTO,
 +                cx.tcx.sess.source_map().guess_head_span(item.span),
 +                "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
 +                |diag| {
 +                    // If the target type is likely foreign mention the orphan rules as it's a common source of confusion
 +                    if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
 +                        diag.help(
 +                            "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
 +                            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
 +                        );
 +                    }
 +
 +                    let message = format!("replace the `Into` implentation 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 {
 +                        diag.help(message);
 +                    }
 +                },
 +            );
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +/// Finds the occurences of `Self` and `self`
 +struct SelfFinder<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    /// Occurences of `Self`
 +    upper: Vec<Span>,
 +    /// Occurences of `self`
 +    lower: Vec<Span>,
 +    /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
 +    /// already named `val`
 +    invalid: bool,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
 +    type NestedFilter = OnlyBodies;
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +
 +    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
 +        for segment in path.segments {
 +            match segment.ident.name {
 +                kw::SelfLower => self.lower.push(segment.ident.span),
 +                kw::SelfUpper => self.upper.push(segment.ident.span),
 +                _ => continue,
 +            }
 +        }
 +
 +        self.invalid |= path.span.from_expansion();
 +        if !self.invalid {
 +            walk_path(self, path);
 +        }
 +    }
 +
 +    fn visit_name(&mut self, name: Symbol) {
 +        if name == sym::val {
 +            self.invalid = true;
 +        }
 +    }
 +}
 +
 +fn convert_to_from(
 +    cx: &LateContext<'_>,
 +    into_trait_seg: &PathSegment<'_>,
 +    target_ty: &Ty<'_>,
 +    self_ty: &Ty<'_>,
 +    impl_item_ref: &ImplItemRef,
 +) -> Option<Vec<(Span, String)>> {
 +    let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
 +    let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
 +    let body = cx.tcx.hir().body(body_id);
 +    let [input] = body.params else { return None };
 +    let PatKind::Binding(.., self_ident, None) = input.pat.kind else { return None };
 +
 +    let from = snippet_opt(cx, self_ty.span)?;
 +    let into = snippet_opt(cx, target_ty.span)?;
 +
 +    let mut suggestions = vec![
 +        // impl Into<T> for U  ->  impl From<T> for U
 +        //      ~~~~                    ~~~~
 +        (into_trait_seg.ident.span, String::from("From")),
 +        // impl Into<T> for U  ->  impl Into<U> for U
 +        //           ~                       ~
 +        (target_ty.span, from.clone()),
 +        // impl Into<T> for U  ->  impl Into<T> for T
 +        //                  ~                       ~
 +        (self_ty.span, into),
 +        // fn into(self) -> T  ->  fn from(self) -> T
 +        //    ~~~~                    ~~~~
 +        (impl_item.ident.span, String::from("from")),
 +        // fn into([mut] self) -> T  ->  fn into([mut] v: T) -> T
 +        //               ~~~~                          ~~~~
 +        (self_ident.span, format!("val: {from}")),
 +        // fn into(self) -> T  ->  fn into(self) -> Self
 +        //                  ~                       ~~~~
 +        (sig.decl.output.span(), String::from("Self")),
 +    ];
 +
 +    let mut finder = SelfFinder {
 +        cx,
 +        upper: Vec::new(),
 +        lower: Vec::new(),
 +        invalid: false,
 +    };
 +    finder.visit_expr(body.value);
 +
 +    if finder.invalid {
 +        return None;
 +    }
 +
 +    // don't try to replace e.g. `Self::default()` with `&[T]::default()`
 +    if !finder.upper.is_empty() && !matches!(self_ty.kind, TyKind::Path(_)) {
 +        return None;
 +    }
 +
 +    for span in finder.upper {
 +        suggestions.push((span, from.clone()));
 +    }
 +    for span in finder.lower {
 +        suggestions.push((span, String::from("val")));
 +    }
 +
 +    Some(suggestions)
 +}
index bf1351829c6a5e2e61755dc873df6494e5009ab5,0000000000000000000000000000000000000000..6e19343931ecb846bc9d9ece97efd37c9f27683b
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,114 @@@
-     #[clippy::version = "1.65.0"]
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::get_parent_expr;
 +use clippy_utils::source::snippet_with_applicability;
 +use if_chain::if_chain;
 +use rustc_ast::ast::{LitIntType, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for implicit saturating addition.
 +    ///
 +    /// ### Why is this bad?
 +    /// The built-in function is more readable and may be faster.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    ///let mut u:u32 = 7000;
 +    ///
 +    /// if u != u32::MAX {
 +    ///     u += 1;
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    ///let mut u:u32 = 7000;
 +    ///
 +    /// u = u.saturating_add(1);
 +    /// ```
++    #[clippy::version = "1.66.0"]
 +    pub IMPLICIT_SATURATING_ADD,
 +    style,
 +    "Perform saturating addition instead of implicitly checking max bound of data type"
 +}
 +declare_lint_pass!(ImplicitSaturatingAdd => [IMPLICIT_SATURATING_ADD]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 +        if_chain! {
 +            if let ExprKind::If(cond, then, None) = expr.kind;
 +            if let ExprKind::DropTemps(expr1) = cond.kind;
 +            if let Some((c, op_node, l)) = get_const(cx, expr1);
 +            if let BinOpKind::Ne | BinOpKind::Lt = op_node;
 +            if let ExprKind::Block(block, None) = then.kind;
 +            if let Block {
 +                stmts:
 +                    [Stmt
 +                        { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }],
 +                        expr: None, ..} |
 +                        Block { stmts: [], expr: Some(ex), ..} = block;
 +            if let ExprKind::AssignOp(op1, target, value) = ex.kind;
 +            let ty = cx.typeck_results().expr_ty(target);
 +            if Some(c) == get_int_max(ty);
 +            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 LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
 +            if block.expr.is_none();
 +            then {
 +                let mut app = Applicability::MachineApplicable;
 +                let code = snippet_with_applicability(cx, target.span, "_", &mut app);
 +                let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id {format!("{{{code} = {code}.saturating_add(1); }}")} else {format!("{code} = {code}.saturating_add(1);")};
 +                span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app);
 +            }
 +        }
 +    }
 +}
 +
 +fn get_int_max(ty: Ty<'_>) -> Option<u128> {
 +    match ty.peel_refs().kind() {
 +        Int(IntTy::I8) => i8::max_value().try_into().ok(),
 +        Int(IntTy::I16) => i16::max_value().try_into().ok(),
 +        Int(IntTy::I32) => i32::max_value().try_into().ok(),
 +        Int(IntTy::I64) => i64::max_value().try_into().ok(),
 +        Int(IntTy::I128) => i128::max_value().try_into().ok(),
 +        Int(IntTy::Isize) => isize::max_value().try_into().ok(),
 +        Uint(UintTy::U8) => u8::max_value().try_into().ok(),
 +        Uint(UintTy::U16) => u16::max_value().try_into().ok(),
 +        Uint(UintTy::U32) => u32::max_value().try_into().ok(),
 +        Uint(UintTy::U64) => u64::max_value().try_into().ok(),
 +        Uint(UintTy::U128) => Some(u128::max_value()),
 +        Uint(UintTy::Usize) => usize::max_value().try_into().ok(),
 +        _ => None,
 +    }
 +}
 +
 +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) {
 +            return Some((c, op.node, l));
 +        };
 +        if let Some((Constant::Int(c), _)) = constant(cx, tr, l) {
 +            return Some((c, invert_op(op.node)?, r));
 +        }
 +    }
 +    None
 +}
 +
 +fn invert_op(op: BinOpKind) -> Option<BinOpKind> {
 +    use rustc_hir::BinOpKind::{Ge, Gt, Le, Lt, Ne};
 +    match op {
 +        Lt => Some(Gt),
 +        Le => Some(Ge),
 +        Ne => Some(Ne),
 +        Ge => Some(Le),
 +        Gt => Some(Lt),
 +        _ => None,
 +    }
 +}
index 4cd7dff4cfd762c95352f230beb6b8b3f0652458,0000000000000000000000000000000000000000..eebfb753a0c5dfdefcb0e542676fcbf9c8faba6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,219 @@@
- use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +//! lint on indexing and slicing operations
 +
 +use clippy_utils::consts::{constant, Constant};
- use rustc_session::{declare_lint_pass, declare_tool_lint};
++use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 +use clippy_utils::higher;
 +use rustc_ast::ast::RangeLimits;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
- declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
++use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for out of bounds array indexing with a constant
 +    /// index.
 +    ///
 +    /// ### Why is this bad?
 +    /// This will always panic at runtime.
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// let x = [1, 2, 3, 4];
 +    ///
 +    /// x[9];
 +    /// &x[2..9];
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = [1, 2, 3, 4];
 +    /// // Index within bounds
 +    ///
 +    /// x[0];
 +    /// x[3];
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OUT_OF_BOUNDS_INDEXING,
 +    correctness,
 +    "out of bounds constant indexing"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of indexing or slicing. Arrays are special cases, this lint
 +    /// does report on arrays if we can tell that slicing operations are in bounds and does not
 +    /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
 +    ///
 +    /// ### Why is this bad?
 +    /// Indexing and slicing can panic at runtime and there are
 +    /// safe alternatives.
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// // Vector
 +    /// let x = vec![0; 5];
 +    ///
 +    /// x[2];
 +    /// &x[2..100];
 +    ///
 +    /// // Array
 +    /// let y = [0, 1, 2, 3];
 +    ///
 +    /// &y[10..100];
 +    /// &y[10..];
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # #![allow(unused)]
 +    ///
 +    /// # let x = vec![0; 5];
 +    /// # let y = [0, 1, 2, 3];
 +    /// x.get(2);
 +    /// x.get(2..100);
 +    ///
 +    /// y.get(10);
 +    /// y.get(10..100);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub INDEXING_SLICING,
 +    restriction,
 +    "indexing/slicing usage"
 +}
 +
-         if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
++impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
++
++#[derive(Copy, Clone)]
++pub struct IndexingSlicing {
++    suppress_restriction_lint_in_const: bool,
++}
++
++impl IndexingSlicing {
++    pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
++        Self {
++            suppress_restriction_lint_in_const,
++        }
++    }
++}
 +
 +impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-                 span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
++        if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) {
 +            return;
 +        }
 +
 +        if let ExprKind::Index(array, index) = &expr.kind {
++            let note = "the suggestion might not be applicable in constant blocks";
 +            let ty = cx.typeck_results().expr_ty(array).peel_refs();
 +            if let Some(range) = higher::Range::hir(index) {
 +                // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
 +                if let ty::Array(_, s) = ty.kind() {
 +                    let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
 +                        size.into()
 +                    } else {
 +                        return;
 +                    };
 +
 +                    let const_range = to_const_range(cx, range, size);
 +
 +                    if let (Some(start), _) = const_range {
 +                        if start > size {
 +                            span_lint(
 +                                cx,
 +                                OUT_OF_BOUNDS_INDEXING,
 +                                range.start.map_or(expr.span, |start| start.span),
 +                                "range is out of bounds",
 +                            );
 +                            return;
 +                        }
 +                    }
 +
 +                    if let (_, Some(end)) = const_range {
 +                        if end > size {
 +                            span_lint(
 +                                cx,
 +                                OUT_OF_BOUNDS_INDEXING,
 +                                range.end.map_or(expr.span, |end| end.span),
 +                                "range is out of bounds",
 +                            );
 +                            return;
 +                        }
 +                    }
 +
 +                    if let (Some(_), Some(_)) = const_range {
 +                        // early return because both start and end are constants
 +                        // and we have proven above that they are in bounds
 +                        return;
 +                    }
 +                }
 +
 +                let help_msg = match (range.start, range.end) {
 +                    (None, Some(_)) => "consider using `.get(..n)`or `.get_mut(..n)` instead",
 +                    (Some(_), None) => "consider using `.get(n..)` or .get_mut(n..)` instead",
 +                    (Some(_), Some(_)) => "consider using `.get(n..m)` or `.get_mut(n..m)` instead",
 +                    (None, None) => return, // [..] is ok.
 +                };
 +
-                 span_lint_and_help(
-                     cx,
-                     INDEXING_SLICING,
-                     expr.span,
-                     "indexing may panic",
-                     None,
-                     "consider using `.get(n)` or `.get_mut(n)` instead",
-                 );
++                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| {
++                    diag.help(help_msg);
++
++                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
++                        diag.note(note);
++                    }
++                });
 +            } else {
 +                // Catchall non-range index, i.e., [n] or [n << m]
 +                if let ty::Array(..) = ty.kind() {
 +                    // Index is a const block.
 +                    if let ExprKind::ConstBlock(..) = index.kind {
 +                        return;
 +                    }
 +                    // Index is a constant uint.
 +                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
 +                        // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
 +                        return;
 +                    }
 +                }
 +
++                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| {
++                    diag.help("consider using `.get(n)` or `.get_mut(n)` instead");
++
++                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
++                        diag.note(note);
++                    }
++                });
 +            }
 +        }
 +    }
 +}
 +
 +/// 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 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 end = match e {
 +        Some(Some(Constant::Int(x))) => {
 +            if range.limits == RangeLimits::Closed {
 +                Some(x + 1)
 +            } else {
 +                Some(x)
 +            }
 +        },
 +        Some(_) => None,
 +        None => Some(array_size),
 +    };
 +
 +    (start, end)
 +}
index 73841f9aa9a2112a626dd86e95b34779d90b33ff,0000000000000000000000000000000000000000..e88d1764a24896a23d168a5b01c2d908e851e804
mode 100644,000000..100644
--- /dev/null
@@@ -1,501 -1,0 +1,509 @@@
- use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet_with_applicability;
-     ItemKind, Mutability, Node, TraitItemRef, TyKind,
++use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefIdSet;
 +use rustc_hir::{
 +    def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
-             format!(
-                 "{op}{}.is_empty()",
-                 snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
-             ),
++    ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{
 +    source_map::{Span, Spanned, Symbol},
 +    symbol::sym,
 +};
++use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for getting the length of something via `.len()`
 +    /// just to compare to zero, and suggests using `.is_empty()` where applicable.
 +    ///
 +    /// ### Why is this bad?
 +    /// Some structures can answer `.is_empty()` much faster
 +    /// than calculating their length. So it is good to get into the habit of using
 +    /// `.is_empty()`, and having it is cheap.
 +    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// if x.len() == 0 {
 +    ///     ..
 +    /// }
 +    /// if y.len() != 0 {
 +    ///     ..
 +    /// }
 +    /// ```
 +    /// instead use
 +    /// ```ignore
 +    /// if x.is_empty() {
 +    ///     ..
 +    /// }
 +    /// if !y.is_empty() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub LEN_ZERO,
 +    style,
 +    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for items that implement `.len()` but not
 +    /// `.is_empty()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is good custom to have both methods, because for
 +    /// some data structures, asking about the length will be a costly operation,
 +    /// whereas `.is_empty()` can usually answer in constant time. Also it used to
 +    /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
 +    /// lint will ignore such entities.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// impl X {
 +    ///     pub fn len(&self) -> usize {
 +    ///         ..
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub LEN_WITHOUT_IS_EMPTY,
 +    style,
 +    "traits or impls with a public `len` method but no corresponding `is_empty` method"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for comparing to an empty slice such as `""` or `[]`,
 +    /// and suggests using `.is_empty()` where applicable.
 +    ///
 +    /// ### Why is this bad?
 +    /// Some structures can answer `.is_empty()` much faster
 +    /// than checking for equality. So it is good to get into the habit of using
 +    /// `.is_empty()`, and having it is cheap.
 +    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```ignore
 +    /// if s == "" {
 +    ///     ..
 +    /// }
 +    ///
 +    /// if arr == [] {
 +    ///     ..
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```ignore
 +    /// if s.is_empty() {
 +    ///     ..
 +    /// }
 +    ///
 +    /// if arr.is_empty() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub COMPARISON_TO_EMPTY,
 +    style,
 +    "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
 +}
 +
 +declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LenZero {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if item.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
 +            check_trait_items(cx, item, trait_items);
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if_chain! {
 +            if item.ident.name == sym::len;
 +            if let ImplItemKind::Fn(sig, _) = &item.kind;
 +            if sig.decl.implicit_self.has_implicit_self();
 +            if cx.effective_visibilities.is_exported(item.owner_id.def_id);
 +            if matches!(sig.decl.output, FnRetTy::Return(_));
 +            if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
 +            if imp.of_trait.is_none();
 +            if let TyKind::Path(ty_path) = &imp.self_ty.kind;
 +            if let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id();
 +            if let Some(local_id) = ty_id.as_local();
 +            let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
 +            if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
 +            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
 +            then {
 +                let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
 +                    Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
 +                    Some(Node::Item(x)) => match x.kind {
 +                        ItemKind::Struct(..) => (x.ident.name, "struct"),
 +                        ItemKind::Enum(..) => (x.ident.name, "enum"),
 +                        ItemKind::Union(..) => (x.ident.name, "union"),
 +                        _ => (x.ident.name, "type"),
 +                    }
 +                    _ => return,
 +                };
 +                check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind)
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
 +            match cmp {
 +                BinOpKind::Eq => {
 +                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
 +                    check_cmp(cx, expr.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
 +                },
 +                BinOpKind::Gt => {
 +                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
 +                    check_cmp(cx, expr.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
 +                },
 +                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
 +                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
 +    fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
 +        item.ident.name == name
 +            && if let AssocItemKind::Fn { has_self } = item.kind {
 +                has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
 +            } else {
 +                false
 +            }
 +    }
 +
 +    // fill the set with current and super traits
 +    fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
 +        if set.insert(traitt) {
 +            for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) {
 +                fill_trait_set(supertrait, set, cx);
 +            }
 +        }
 +    }
 +
 +    if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id)
 +        && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
 +    {
 +        let mut current_and_super_traits = DefIdSet::default();
 +        fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
 +        let is_empty = sym!(is_empty);
 +
 +        let is_empty_method_found = current_and_super_traits
 +            .iter()
 +            .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
 +            .any(|i| {
 +                i.kind == ty::AssocKind::Fn
 +                    && i.fn_has_self_parameter
 +                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
 +            });
 +
 +        if !is_empty_method_found {
 +            span_lint(
 +                cx,
 +                LEN_WITHOUT_IS_EMPTY,
 +                visited_trait.span,
 +                &format!(
 +                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
 +                    visited_trait.ident.name
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +enum LenOutput<'tcx> {
 +    Integral,
 +    Option(DefId),
 +    Result(DefId, Ty<'tcx>),
 +}
 +fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
 +    match *sig.output().kind() {
 +        ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
 +        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => {
 +            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did()))
 +        },
 +        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => subs
 +            .type_at(0)
 +            .is_integral()
 +            .then(|| LenOutput::Result(adt.did(), subs.type_at(1))),
 +        _ => None,
 +    }
 +}
 +
 +impl<'tcx> LenOutput<'tcx> {
 +    fn matches_is_empty_output(self, ty: Ty<'tcx>) -> bool {
 +        match (self, ty.kind()) {
 +            (_, &ty::Bool) => true,
 +            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(),
 +            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did() => {
 +                subs.type_at(0).is_bool() && subs.type_at(1) == err_ty
 +            },
 +            _ => false,
 +        }
 +    }
 +
 +    fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
 +        let self_ref = match self_kind {
 +            ImplicitSelfKind::ImmRef => "&",
 +            ImplicitSelfKind::MutRef => "&mut ",
 +            _ => "",
 +        };
 +        match self {
 +            Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"),
 +            Self::Option(_) => {
 +                format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option<bool>")
 +            },
 +            Self::Result(..) => {
 +                format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result<bool>")
 +            },
 +        }
 +    }
 +}
 +
 +/// Checks if the given signature matches the expectations for `is_empty`
 +fn check_is_empty_sig<'tcx>(sig: FnSig<'tcx>, self_kind: ImplicitSelfKind, len_output: LenOutput<'tcx>) -> bool {
 +    match &**sig.inputs_and_output {
 +        [arg, res] if len_output.matches_is_empty_output(*res) => {
 +            matches!(
 +                (arg.kind(), self_kind),
 +                (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
 +                    | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef)
 +            ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the given type has an `is_empty` method with the appropriate signature.
 +fn check_for_is_empty<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    self_kind: ImplicitSelfKind,
 +    output: LenOutput<'tcx>,
 +    impl_ty: DefId,
 +    item_name: Symbol,
 +    item_kind: &str,
 +) {
 +    let is_empty = Symbol::intern("is_empty");
 +    let is_empty = cx
 +        .tcx
 +        .inherent_impls(impl_ty)
 +        .iter()
 +        .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
 +        .find(|item| item.kind == AssocKind::Fn);
 +
 +    let (msg, is_empty_span, self_kind) = match is_empty {
 +        None => (
 +            format!(
 +                "{item_kind} `{}` has a public `len` method, but no `is_empty` method",
 +                item_name.as_str(),
 +            ),
 +            None,
 +            None,
 +        ),
 +        Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => (
 +            format!(
 +                "{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
 +                item_name.as_str(),
 +            ),
 +            Some(cx.tcx.def_span(is_empty.def_id)),
 +            None,
 +        ),
 +        Some(is_empty)
 +            if !(is_empty.fn_has_self_parameter
 +                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
 +        {
 +            (
 +                format!(
 +                    "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
 +                    item_name.as_str(),
 +                ),
 +                Some(cx.tcx.def_span(is_empty.def_id)),
 +                Some(self_kind),
 +            )
 +        },
 +        Some(_) => return,
 +    };
 +
 +    span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, &msg, |db| {
 +        if let Some(span) = is_empty_span {
 +            db.span_note(span, "`is_empty` defined here");
 +        }
 +        if let Some(self_kind) = self_kind {
 +            db.note(&output.expected_sig(self_kind));
 +        }
 +    });
 +}
 +
 +fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
 +    if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
 +        // check if we are in an is_empty() method
 +        if let Some(name) = get_item_name(cx, method) {
 +            if name.as_str() == "is_empty" {
 +                return;
 +            }
 +        }
 +
 +        check_len(
 +            cx,
 +            span,
 +            method_path.ident.name,
 +            receiver,
 +            args,
 +            &lit.node,
 +            op,
 +            compare_to,
 +        );
 +    } else {
 +        check_empty_expr(cx, span, method, lit, op);
 +    }
 +}
 +
 +// FIXME(flip1995): Figure out how to reduce the number of arguments
 +#[allow(clippy::too_many_arguments)]
 +fn check_len(
 +    cx: &LateContext<'_>,
 +    span: Span,
 +    method_name: Symbol,
 +    receiver: &Expr<'_>,
 +    args: &[Expr<'_>],
 +    lit: &LitKind,
 +    op: &str,
 +    compare_to: u32,
 +) {
 +    if let LitKind::Int(lit, _) = *lit {
 +        // check if length is compared to the specified number
 +        if lit != u128::from(compare_to) {
 +            return;
 +        }
 +
 +        if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                LEN_ZERO,
 +                span,
 +                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
 +                &format!("using `{op}is_empty` is clearer and more explicit"),
 +                format!(
 +                    "{op}{}.is_empty()",
 +                    snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
 +                ),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
 +    if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
 +        let mut applicability = Applicability::MachineApplicable;
++
++        let lit1 = peel_ref_operators(cx, lit1);
++        let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
++
++        // Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
++        // cause the code to dereference boolean(won't compile).
++        if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
++            lit_str = Cow::from(format!("({lit_str})"));
++        }
++
 +        span_lint_and_sugg(
 +            cx,
 +            COMPARISON_TO_EMPTY,
 +            span,
 +            "comparison to empty slice",
 +            &format!("using `{op}is_empty` is clearer and more explicit"),
++            format!("{op}{lit_str}.is_empty()"),
 +            applicability,
 +        );
 +    }
 +}
 +
 +fn is_empty_string(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Lit(ref lit) = expr.kind {
 +        if let LitKind::Str(lit, _) = lit.node {
 +            let lit = lit.as_str();
 +            return lit.is_empty();
 +        }
 +    }
 +    false
 +}
 +
 +fn is_empty_array(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Array(arr) = expr.kind {
 +        return arr.is_empty();
 +    }
 +    false
 +}
 +
 +/// Checks if this type has an `is_empty` method.
 +fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
 +    fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
 +        if item.kind == ty::AssocKind::Fn {
 +            let sig = cx.tcx.fn_sig(item.def_id);
 +            let ty = sig.skip_binder();
 +            ty.inputs().len() == 1
 +        } else {
 +            false
 +        }
 +    }
 +
 +    /// Checks the inherent impl's items for an `is_empty(self)` method.
 +    fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
 +        let is_empty = sym!(is_empty);
 +        cx.tcx.inherent_impls(id).iter().any(|imp| {
 +            cx.tcx
 +                .associated_items(*imp)
 +                .filter_by_name_unhygienic(is_empty)
 +                .any(|item| is_is_empty(cx, item))
 +        })
 +    }
 +
 +    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
 +    match ty.kind() {
 +        ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
 +            let is_empty = sym!(is_empty);
 +            cx.tcx
 +                .associated_items(principal.def_id())
 +                .filter_by_name_unhygienic(is_empty)
 +                .any(|item| is_is_empty(cx, item))
 +        }),
 +        ty::Alias(ty::Projection, ref proj) => has_is_empty_impl(cx, proj.def_id),
 +        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
 +        ty::Array(..) | ty::Slice(..) | ty::Str => true,
 +        _ => false,
 +    }
 +}
index 7b17d8a156d5af6ddb3b9417b7990e65d2a3d5ee,0000000000000000000000000000000000000000..39850d598038f1b3d15fce37e068528a3c9b1c8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,948 -1,0 +1,966 @@@
- mod almost_complete_letter_range;
 +#![feature(array_windows)]
 +#![feature(binary_heap_into_iter_sorted)]
 +#![feature(box_patterns)]
 +#![feature(control_flow_enum)]
 +#![feature(drain_filter)]
 +#![feature(iter_intersperse)]
 +#![feature(let_chains)]
 +#![feature(lint_reasons)]
 +#![feature(never_type)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![feature(stmt_expr_attributes)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +// Disable this rustc lint for now, as it was also done in rustc
 +#![allow(rustc::potential_query_instability)]
 +
 +// 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_arena;
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_data_structures;
 +extern crate rustc_driver;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_analysis;
 +extern crate rustc_hir_pretty;
 +extern crate rustc_hir_typeck;
 +extern crate rustc_index;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_parse;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +
 +#[macro_use]
 +extern crate clippy_utils;
 +#[macro_use]
 +extern crate declare_clippy_lint;
 +
 +use std::io;
 +use std::path::PathBuf;
 +
 +use clippy_utils::msrvs::Msrv;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_lint::{Lint, LintId};
 +use rustc_session::Session;
 +
 +#[cfg(feature = "internal")]
 +pub mod deprecated_lints;
 +#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 +mod utils;
 +
 +mod declared_lints;
 +mod renamed_lints;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
-             arithmetic_side_effects_allowed.clone(),
++mod almost_complete_range;
 +mod approx_const;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assertions_on_result_states;
 +mod async_yields_async;
 +mod attrs;
 +mod await_holding_invalid;
 +mod blocks_in_if_conditions;
 +mod bool_assert_comparison;
 +mod bool_to_int_with_if;
 +mod booleans;
 +mod borrow_deref_ref;
 +mod box_default;
 +mod cargo;
 +mod casts;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod crate_in_macro_def;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod default_instead_of_iter_empty;
 +mod default_numeric_fallback;
 +mod default_union_representation;
 +mod dereference;
 +mod derivable_impls;
 +mod derive;
 +mod disallowed_macros;
 +mod disallowed_methods;
 +mod disallowed_names;
 +mod disallowed_script_idents;
 +mod disallowed_types;
 +mod doc;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duplicate_mod;
 +mod else_if_without_else;
 +mod empty_drop;
 +mod empty_enum;
 +mod empty_structs_with_brackets;
 +mod entry;
 +mod enum_clike;
 +mod enum_variants;
 +mod equatable_if_let;
 +mod escape;
 +mod eta_reduction;
 +mod excessive_bools;
 +mod exhaustive_items;
 +mod exit;
 +mod explicit_write;
 +mod fallible_impl_from;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod format_args;
 +mod format_impl;
 +mod format_push_string;
 +mod formatting;
 +mod from_over_into;
 +mod from_raw_with_void_ptr;
 +mod from_str_radix_10;
 +mod functions;
 +mod future_not_send;
 +mod if_let_mutex;
 +mod if_not_else;
 +mod if_then_some_else_none;
 +mod implicit_hasher;
 +mod implicit_return;
 +mod implicit_saturating_add;
 +mod implicit_saturating_sub;
 +mod inconsistent_struct_constructor;
 +mod index_refutable_slice;
 +mod indexing_slicing;
 +mod infinite_iter;
 +mod inherent_impl;
 +mod inherent_to_string;
 +mod init_numbered_fields;
 +mod inline_fn_without_body;
 +mod instant_subtraction;
 +mod int_plus_one;
 +mod invalid_upcast_comparisons;
 +mod invalid_utf8_in_unchecked;
 +mod items_after_statements;
 +mod iter_not_returning_iterator;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_include_file;
 +mod large_stack_arrays;
 +mod len_zero;
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
 +mod manual_assert;
 +mod manual_async_fn;
 +mod manual_bits;
 +mod manual_clamp;
 +mod manual_is_ascii_check;
 +mod manual_let_else;
 +mod manual_non_exhaustive;
 +mod manual_rem_euclid;
 +mod manual_retain;
 +mod manual_string_new;
 +mod manual_strip;
 +mod map_unit_fn;
 +mod match_result_ok;
 +mod matches;
 +mod mem_forget;
 +mod mem_replace;
 +mod methods;
 +mod minmax;
 +mod misc;
 +mod misc_early;
 +mod mismatching_type_param_order;
 +mod missing_const_for_fn;
 +mod missing_doc;
 +mod missing_enforced_import_rename;
 +mod missing_inline;
 +mod missing_trait_methods;
 +mod mixed_read_write_in_expression;
 +mod module_style;
 +mod multi_assignments;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bool;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_for_each;
 +mod needless_late_init;
 +mod needless_parens_on_range_literals;
 +mod needless_pass_by_value;
 +mod needless_question_mark;
 +mod needless_update;
 +mod neg_cmp_op_on_partial_ord;
 +mod neg_multiply;
 +mod new_without_default;
 +mod no_effect;
 +mod non_copy_const;
 +mod non_expressive_names;
 +mod non_octal_unix_permissions;
 +mod non_send_fields_in_send_ty;
 +mod nonstandard_macro_braces;
 +mod octal_escapes;
 +mod only_used_in_recursion;
 +mod operators;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partial_pub_fields;
 +mod partialeq_ne_impl;
 +mod partialeq_to_none;
 +mod pass_by_ref_or_value;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_offset_with_cast;
 +mod pub_use;
 +mod question_mark;
 +mod ranges;
 +mod rc_clone_in_vec_init;
 +mod read_zero_byte_vec;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_else;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_slicing;
 +mod redundant_static_lifetimes;
 +mod ref_option_ref;
 +mod reference;
 +mod regex;
 +mod return_self_not_must_use;
 +mod returns;
 +mod same_name_method;
 +mod self_named_constructors;
++mod semicolon_block;
 +mod semicolon_if_nothing_returned;
 +mod serde_api;
 +mod shadow;
 +mod single_char_lifetime_names;
 +mod single_component_path_imports;
 +mod size_of_in_element_count;
 +mod slow_vector_initialization;
 +mod std_instead_of_core;
 +mod strings;
 +mod strlen_on_c_strings;
 +mod suspicious_operation_groupings;
 +mod suspicious_trait_impl;
 +mod suspicious_xor_used_as_pow;
 +mod swap;
 +mod swap_ptr_to_ref;
 +mod tabs_in_doc_comments;
 +mod temporary_assignment;
 +mod to_digit_is_some;
 +mod trailing_empty_array;
 +mod trait_bounds;
 +mod transmute;
 +mod types;
 +mod undocumented_unsafe_blocks;
 +mod unicode;
 +mod uninit_vec;
 +mod unit_return_expecting_ord;
 +mod unit_types;
 +mod unnamed_address;
 +mod unnecessary_owned_empty_strings;
 +mod unnecessary_self_imports;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_async;
 +mod unused_io_amount;
 +mod unused_peekable;
 +mod unused_rounding;
 +mod unused_self;
 +mod unused_unit;
 +mod unwrap;
 +mod unwrap_in_result;
 +mod upper_case_acronyms;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_init_then_push;
 +mod wildcard_imports;
 +mod write;
 +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};
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
 +    let msrv = Msrv::read(&conf.msrv, sess);
 +    let msrv = move || msrv.clone();
 +
 +    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
 +    let file_name = match path {
 +        Ok(Some(path)) => path,
 +        Ok(None) => return Conf::default(),
 +        Err(error) => {
 +            sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
 +                .emit();
 +            return Conf::default();
 +        },
 +    };
 +
 +    let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
 +    // all conf errors are non-fatal, we just use the default conf in case of error
 +    for error in errors {
 +        sess.err(format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            format_error(error)
 +        ));
 +    }
 +
 +    for warning in warnings {
 +        sess.struct_warn(format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            format_error(warning)
 +        ))
 +        .emit();
 +    }
 +
 +    conf
 +}
 +
 +#[derive(Default)]
 +struct RegistrationGroups {
 +    all: Vec<LintId>,
 +    cargo: Vec<LintId>,
 +    complexity: Vec<LintId>,
 +    correctness: Vec<LintId>,
 +    nursery: Vec<LintId>,
 +    pedantic: Vec<LintId>,
 +    perf: Vec<LintId>,
 +    restriction: Vec<LintId>,
 +    style: Vec<LintId>,
 +    suspicious: Vec<LintId>,
 +    #[cfg(feature = "internal")]
 +    internal: Vec<LintId>,
 +}
 +
 +impl RegistrationGroups {
 +    #[rustfmt::skip]
 +    fn register(self, store: &mut rustc_lint::LintStore) {
 +        store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
 +        store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
 +        store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
 +        store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
 +        store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
 +        store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
 +        store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
 +        store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
 +        store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
 +        store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
 +        #[cfg(feature = "internal")]
 +        store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal);
 +    }
 +}
 +
 +#[derive(Copy, Clone)]
 +pub(crate) enum LintCategory {
 +    Cargo,
 +    Complexity,
 +    Correctness,
 +    Nursery,
 +    Pedantic,
 +    Perf,
 +    Restriction,
 +    Style,
 +    Suspicious,
 +    #[cfg(feature = "internal")]
 +    Internal,
 +}
 +#[allow(clippy::enum_glob_use)]
 +use LintCategory::*;
 +
 +impl LintCategory {
 +    fn is_all(self) -> bool {
 +        matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
 +    }
 +
 +    fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
 +        match self {
 +            Cargo => &mut groups.cargo,
 +            Complexity => &mut groups.complexity,
 +            Correctness => &mut groups.correctness,
 +            Nursery => &mut groups.nursery,
 +            Pedantic => &mut groups.pedantic,
 +            Perf => &mut groups.perf,
 +            Restriction => &mut groups.restriction,
 +            Style => &mut groups.style,
 +            Suspicious => &mut groups.suspicious,
 +            #[cfg(feature = "internal")]
 +            Internal => &mut groups.internal,
 +        }
 +    }
 +}
 +
 +pub(crate) struct LintInfo {
 +    /// Double reference to maintain pointer equality
 +    lint: &'static &'static Lint,
 +    category: LintCategory,
 +    explanation: &'static str,
 +}
 +
 +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),
 +        None => println!("unknown lint: {name}"),
 +    }
 +}
 +
 +fn register_categories(store: &mut rustc_lint::LintStore) {
 +    let mut groups = RegistrationGroups::default();
 +
 +    for LintInfo { lint, category, .. } in declared_lints::LINTS {
 +        if category.is_all() {
 +            groups.all.push(LintId::of(lint));
 +        }
 +
 +        category.group(&mut groups).push(LintId::of(lint));
 +    }
 +
 +    let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
 +
 +    store.register_lints(&lints);
 +    groups.register(store);
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[expect(clippy::too_many_lines)]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +    register_categories(store);
 +
 +    include!("lib.deprecated.rs");
 +
 +    #[cfg(feature = "internal")]
 +    {
 +        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
 +            store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
 +            return;
 +        }
 +    }
 +
 +    // all the internal lints
 +    #[cfg(feature = "internal")]
 +    {
 +        store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal));
 +        store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
 +        store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
 +        store.register_late_pass(|_| {
 +            Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
 +        });
 +        store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle));
 +        store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
 +        store.register_late_pass(|_| {
 +            Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
 +        });
 +        store.register_late_pass(|_| {
 +            Box::<utils::internal_lints::lint_without_lint_pass::LintWithoutLintPass>::default()
 +        });
 +        store.register_late_pass(|_| Box::<utils::internal_lints::unnecessary_def_path::UnnecessaryDefPath>::default());
 +        store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass));
 +        store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl));
 +    }
 +
 +    let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
++    let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone();
++    let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone();
 +    store.register_late_pass(move |_| {
 +        Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
-     store.register_late_pass(|_| Box::new(misc::MiscLints));
++            arithmetic_side_effects_allowed
++                .iter()
++                .flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
++                .chain(arithmetic_side_effects_allowed_binary.clone())
++                .collect(),
++            arithmetic_side_effects_allowed
++                .iter()
++                .chain(arithmetic_side_effects_allowed_unary.iter())
++                .cloned()
++                .collect(),
 +        ))
 +    });
 +    store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
 +    store.register_late_pass(|_| Box::new(utils::author::Author));
 +    let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
 +    store.register_late_pass(move |_| {
 +        Box::new(await_holding_invalid::AwaitHolding::new(
 +            await_holding_invalid_types.clone(),
 +        ))
 +    });
 +    store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
 +    let vec_box_size_threshold = conf.vec_box_size_threshold;
 +    let type_complexity_threshold = conf.type_complexity_threshold;
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move |_| {
 +        Box::new(types::Types::new(
 +            vec_box_size_threshold,
 +            type_complexity_threshold,
 +            avoid_breaking_exported_api,
 +        ))
 +    });
 +    store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
 +    store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
 +    store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
 +    store.register_late_pass(|_| Box::new(ptr::Ptr));
 +    store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
 +    store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
 +    store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
-     store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
++    store.register_late_pass(|_| Box::<misc::LintPass>::default());
 +    store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
 +    store.register_late_pass(|_| Box::new(mut_mut::MutMut));
 +    store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
 +    store.register_late_pass(|_| Box::new(len_zero::LenZero));
 +    store.register_late_pass(|_| Box::new(attrs::Attributes));
 +    store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
 +    store.register_late_pass(|_| Box::new(unicode::Unicode));
 +    store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
 +    store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
 +    store.register_late_pass(|_| Box::new(strings::StringAdd));
 +    store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
 +    store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
 +    store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
 +    store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
 +    store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
 +    store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 +
 +    let msrv = Msrv::read(&conf.msrv, sess);
 +    let msrv = move || msrv.clone();
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    let allow_expect_in_tests = conf.allow_expect_in_tests;
 +    let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
++    let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
 +    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
 +    store.register_late_pass(move |_| {
 +        Box::new(methods::Methods::new(
 +            avoid_breaking_exported_api,
 +            msrv(),
 +            allow_expect_in_tests,
 +            allow_unwrap_in_tests,
 +        ))
 +    });
 +    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
 +    let matches_for_let_else = conf.matches_for_let_else;
 +    store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), matches_for_let_else)));
 +    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
 +    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv())));
 +    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
 +    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv())));
 +    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
 +    store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
 +    store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
 +    let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
 +    store.register_late_pass(move |_| {
 +        Box::new(index_refutable_slice::IndexRefutableSlice::new(
 +            max_suggested_slice_pattern_length,
 +            msrv(),
 +        ))
 +    });
 +    store.register_late_pass(|_| Box::<shadow::Shadow>::default());
 +    store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
 +    store.register_late_pass(|_| Box::new(loops::Loops));
 +    store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
 +    store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
 +    store.register_late_pass(|_| Box::new(entry::HashMapPass));
 +    store.register_late_pass(|_| Box::new(minmax::MinMaxPass));
 +    store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv));
 +    store.register_late_pass(|_| Box::new(mutex_atomic::Mutex));
 +    store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate));
 +    store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
 +    store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
 +    store.register_late_pass(|_| Box::new(no_effect::NoEffect));
 +    store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
 +    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move |_| {
 +        Box::new(cognitive_complexity::CognitiveComplexity::new(
 +            cognitive_complexity_threshold,
 +        ))
 +    });
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
 +    store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack }));
 +    store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
 +    store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
 +    store.register_late_pass(|_| Box::new(derive::Derive));
 +    store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls));
 +    store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
 +    store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
 +    store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
 +    store.register_late_pass(|_| Box::new(regex::Regex));
 +    store.register_late_pass(|_| Box::new(copies::CopyAndPaste));
 +    store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
 +    store.register_late_pass(|_| Box::new(format::UselessFormat));
 +    store.register_late_pass(|_| Box::new(swap::Swap));
 +    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
 +    store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
 +    let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
 +    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold = conf.too_many_lines_threshold;
 +    let large_error_threshold = conf.large_error_threshold;
 +    store.register_late_pass(move |_| {
 +        Box::new(functions::Functions::new(
 +            too_many_arguments_threshold,
 +            too_many_lines_threshold,
 +            large_error_threshold,
 +        ))
 +    });
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
 +    store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
 +    store.register_late_pass(|_| Box::new(mem_forget::MemForget));
 +    store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
 +    store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
 +    store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
 +    store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
 +    store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
 +    store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
 +    store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
 +    store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
 +    store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
 +    store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
 +    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
 +        conf.trivial_copy_size_limit,
 +        conf.pass_by_value_size_limit,
 +        conf.avoid_breaking_exported_api,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move |_| Box::new(pass_by_ref_or_value));
 +    store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
 +    store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
 +    store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
 +    store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
 +    store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
 +    store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
 +    store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
 +    store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
 +    store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
 +    store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
 +    store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
 +    store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
 +    store.register_late_pass(|_| Box::new(unwrap::Unwrap));
-     store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
++    store.register_late_pass(move |_| {
++        Box::new(indexing_slicing::IndexingSlicing::new(
++            suppress_restriction_lint_in_const,
++        ))
++    });
 +    store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
 +    store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
 +    store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
 +    store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
 +    store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
 +    store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
 +    store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
 +    store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
 +    store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
 +    let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
 +    store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
 +    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
 +    store.register_early_pass(|| Box::new(double_parens::DoubleParens));
 +    store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
 +    store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
 +    store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
 +    store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
 +    store.register_early_pass(|| Box::new(formatting::Formatting));
 +    store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
 +    store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
 +    store.register_late_pass(|_| Box::new(returns::Return));
 +    store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
 +    store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
 +    store.register_early_pass(|| Box::new(precedence::Precedence));
 +    store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
 +    store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
 +    store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
 +    store.register_late_pass(|_| Box::new(create_dir::CreateDir));
 +    store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
 +    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
 +    store.register_early_pass(move || {
 +        Box::new(literal_representation::LiteralDigitGrouping::new(
 +            literal_representation_lint_fraction_readability,
 +        ))
 +    });
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || {
 +        Box::new(literal_representation::DecimalLiteralRepresentation::new(
 +            literal_representation_threshold,
 +        ))
 +    });
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_late_pass(move |_| {
 +        Box::new(enum_variants::EnumVariantNames::new(
 +            enum_variant_name_threshold,
 +            avoid_breaking_exported_api,
 +        ))
 +    });
 +    store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
 +    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
 +    store.register_late_pass(move |_| {
 +        Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
 +            avoid_breaking_exported_api,
 +            upper_case_acronyms_aggressive,
 +        ))
 +    });
 +    store.register_late_pass(|_| Box::<default::Default>::default());
 +    store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
 +    store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
 +    store.register_late_pass(|_| Box::new(exit::Exit));
 +    store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
 +    store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
 +    store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
 +    store.register_early_pass(|| Box::new(as_conversions::AsConversions));
 +    store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
 +    store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_late_pass(move |_| {
 +        Box::new(excessive_bools::ExcessiveBools::new(
 +            max_struct_bools,
 +            max_fn_params_bools,
 +        ))
 +    });
 +    store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
 +    store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
 +    store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
 +    store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv())));
 +    store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
 +    store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
 +    store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
 +    store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
 +    store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
 +    store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
 +    store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || {
 +        Box::new(non_expressive_names::NonExpressiveNames {
 +            single_char_binding_names_threshold,
 +        })
 +    });
 +    let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
 +    store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
 +    store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
 +    store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
 +    store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
 +    store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
 +    let disallowed_macros = conf.disallowed_macros.clone();
 +    store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
 +    let disallowed_methods = conf.disallowed_methods.clone();
 +    store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
 +    store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
 +    store.register_late_pass(|_| Box::new(strings::StrToString));
 +    store.register_late_pass(|_| Box::new(strings::StringToString));
 +    store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues));
 +    store.register_late_pass(|_| Box::<vec_init_then_push::VecInitThenPush>::default());
 +    store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
 +    store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
 +    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
 +    store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
 +    store.register_early_pass(move || Box::new(module_style::ModStyle));
 +    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
 +    let disallowed_types = conf.disallowed_types.clone();
 +    store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
 +    let import_renames = conf.enforced_import_renames.clone();
 +    store.register_late_pass(move |_| {
 +        Box::new(missing_enforced_import_rename::ImportRename::new(
 +            import_renames.clone(),
 +        ))
 +    });
 +    let scripts = conf.allowed_scripts.clone();
 +    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
 +    store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
 +    store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
 +    store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
 +    store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
 +    let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
 +    store.register_late_pass(move |_| {
 +        Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
 +            enable_raw_pointer_heuristic_for_send,
 +        ))
 +    });
 +    store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
 +    let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
 +    store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
 +    store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
 +    store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
 +    store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
 +    store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
 +    store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
 +    store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
 +    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
 +    store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
 +    store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
 +    let allow_dbg_in_tests = conf.allow_dbg_in_tests;
 +    store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
 +    let allow_print_in_tests = conf.allow_print_in_tests;
 +    store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
 +    let cargo_ignore_publish = conf.cargo_ignore_publish;
 +    store.register_late_pass(move |_| {
 +        Box::new(cargo::Cargo {
 +            ignore_publish: cargo_ignore_publish,
 +        })
 +    });
 +    store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
 +    store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
 +    store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
 +    store.register_early_pass(|| Box::new(pub_use::PubUse));
 +    store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
 +    let max_include_file_size = conf.max_include_file_size;
 +    store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
 +    store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
 +    store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
 +    store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
 +    store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
++    store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
 +    store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
 +    store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
 +    store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
 +    store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
 +    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
 +    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
 +    store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
 +    store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
 +    store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
 +    store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
 +    store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv())));
 +    store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
 +    store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
 +    store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
 +    store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
 +    store.register_late_pass(|_| Box::new(box_default::BoxDefault));
 +    store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
 +    store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
 +    store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
 +    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));
 +    // add lints here, do not remove this comment, it's used in `new_lint`
 +}
 +
 +#[rustfmt::skip]
 +fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_removed(
 +        "should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "reverse_range_loop",
 +        "this lint is now included in reversed_empty_ranges",
 +    );
 +}
 +
 +/// Register renamed lints.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
 +    for (old_name, new_name) in renamed_lints::RENAMED_LINTS {
 +        ls.register_renamed(old_name, new_name);
 +    }
 +}
 +
 +// only exists to let the dogfood integration test works.
 +// Don't run clippy as an executable directly
 +#[allow(dead_code)]
 +fn main() {
 +    panic!("Please use the cargo-clippy executable");
 +}
index b6f4cf7bbb37f149eccda55bbc0ef40b2f08def9,0000000000000000000000000000000000000000..28ee24309cc467e57c6f374f8b0d86a314134d57
mode 100644,000000..100644
--- /dev/null
@@@ -1,357 -1,0 +1,353 @@@
-     done: bool,
 +use clippy_utils::ty::{has_iter_method, implements_trait};
 +use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{LitIntType, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor};
 +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt};
 +use rustc_hir_analysis::hir_ty_to_ty;
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::nested_filter;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::symbol::{sym, Symbol};
 +use std::iter::Iterator;
 +
 +#[derive(Debug, PartialEq, Eq)]
 +enum IncrementVisitorVarState {
 +    Initial,  // Not examined yet
 +    IncrOnce, // Incremented exactly once, may be a loop counter
 +    DontWarn,
 +}
 +
 +/// Scan a for loop for variables that are incremented exactly once and not used after that.
 +pub(super) struct IncrementVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,                  // context reference
 +    states: HirIdMap<IncrementVisitorVarState>, // incremented variables
 +    depth: u32,                                 // depth of conditional expressions
-             done: false,
 +}
 +
 +impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
 +    pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            states: HirIdMap::default(),
 +            depth: 0,
-         if self.done {
-             return;
-         }
 +        }
 +    }
 +
 +    pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 +        self.states.into_iter().filter_map(|(id, state)| {
 +            if state == IncrementVisitorVarState::IncrOnce {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-             self.done = true;
 +        // If node is a variable
 +        if let Some(def_id) = path_to_local(expr) {
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial);
 +                if *state == IncrementVisitorVarState::IncrOnce {
 +                    *state = IncrementVisitorVarState::DontWarn;
 +                    return;
 +                }
 +
 +                match parent.kind {
 +                    ExprKind::AssignOp(op, lhs, rhs) => {
 +                        if lhs.hir_id == expr.hir_id {
 +                            *state = if op.node == BinOpKind::Add
 +                                && is_integer_const(self.cx, rhs, 1)
 +                                && *state == IncrementVisitorVarState::Initial
 +                                && self.depth == 0
 +                            {
 +                                IncrementVisitorVarState::IncrOnce
 +                            } else {
 +                                // Assigned some other value or assigned multiple times
 +                                IncrementVisitorVarState::DontWarn
 +                            };
 +                        }
 +                    },
 +                    ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
 +                        *state = IncrementVisitorVarState::DontWarn;
 +                    },
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        *state = IncrementVisitorVarState::DontWarn;
 +                    },
 +                    _ => (),
 +                }
 +            }
 +
 +            walk_expr(self, expr);
 +        } else if is_loop(expr) || is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +        } else if let ExprKind::Continue(_) = expr.kind {
++            // If we see a `continue` block, then we increment depth so that the IncrementVisitor
++            // state will be set to DontWarn if we see the variable being modified anywhere afterwards.
++            self.depth += 1;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +}
 +
 +enum InitializeVisitorState<'hir> {
 +    Initial,                            // Not examined yet
 +    Declared(Symbol, Option<Ty<'hir>>), // Declared but not (yet) initialized
 +    Initialized {
 +        name: Symbol,
 +        ty: Option<Ty<'hir>>,
 +        initializer: &'hir Expr<'hir>,
 +    },
 +    DontWarn,
 +}
 +
 +/// Checks whether a variable is initialized at the start of a loop and not modified
 +/// and used after the loop.
 +pub(super) struct InitializeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,  // context reference
 +    end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here.
 +    var_id: HirId,
 +    state: InitializeVisitorState<'tcx>,
 +    depth: u32, // depth of conditional expressions
 +    past_loop: bool,
 +}
 +
 +impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
 +    pub(super) fn new(cx: &'a LateContext<'tcx>, end_expr: &'tcx Expr<'tcx>, var_id: HirId) -> Self {
 +        Self {
 +            cx,
 +            end_expr,
 +            var_id,
 +            state: InitializeVisitorState::Initial,
 +            depth: 0,
 +            past_loop: false,
 +        }
 +    }
 +
 +    pub(super) fn get_result(&self) -> Option<(Symbol, Option<Ty<'tcx>>, &'tcx Expr<'tcx>)> {
 +        if let InitializeVisitorState::Initialized { name, ty, initializer } = self.state {
 +            Some((name, ty, initializer))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
 +    type NestedFilter = nested_filter::OnlyBodies;
 +
 +    fn visit_local(&mut self, l: &'tcx Local<'_>) {
 +        // Look for declarations of the variable
 +        if_chain! {
 +            if l.pat.hir_id == self.var_id;
 +            if let PatKind::Binding(.., ident, _) = l.pat.kind;
 +            then {
 +                let ty = l.ty.map(|ty| hir_ty_to_ty(self.cx.tcx, ty));
 +
 +                self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| {
 +                    InitializeVisitorState::Initialized {
 +                        initializer: init,
 +                        ty,
 +                        name: ident.name,
 +                    }
 +                })
 +            }
 +        }
 +
 +        walk_local(self, l);
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if matches!(self.state, InitializeVisitorState::DontWarn) {
 +            return;
 +        }
 +        if expr.hir_id == self.end_expr.hir_id {
 +            self.past_loop = true;
 +            return;
 +        }
 +        // No need to visit expressions before the variable is
 +        // declared
 +        if matches!(self.state, InitializeVisitorState::Initial) {
 +            return;
 +        }
 +
 +        // If node is the desired variable, see how it's used
 +        if path_to_local_id(expr, self.var_id) {
 +            if self.past_loop {
 +                self.state = InitializeVisitorState::DontWarn;
 +                return;
 +            }
 +
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                match parent.kind {
 +                    ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = InitializeVisitorState::DontWarn;
 +                    },
 +                    ExprKind::Assign(lhs, rhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = if self.depth == 0 {
 +                            match self.state {
 +                                InitializeVisitorState::Declared(name, mut ty) => {
 +                                    if ty.is_none() {
 +                                        if let ExprKind::Lit(Spanned {
 +                                            node: LitKind::Int(_, LitIntType::Unsuffixed),
 +                                            ..
 +                                        }) = rhs.kind
 +                                        {
 +                                            ty = None;
 +                                        } else {
 +                                            ty = self.cx.typeck_results().expr_ty_opt(rhs);
 +                                        }
 +                                    }
 +
 +                                    InitializeVisitorState::Initialized {
 +                                        initializer: rhs,
 +                                        ty,
 +                                        name,
 +                                    }
 +                                },
 +                                InitializeVisitorState::Initialized { ty, name, .. } => {
 +                                    InitializeVisitorState::Initialized {
 +                                        initializer: rhs,
 +                                        ty,
 +                                        name,
 +                                    }
 +                                },
 +                                _ => InitializeVisitorState::DontWarn,
 +                            }
 +                        } else {
 +                            InitializeVisitorState::DontWarn
 +                        }
 +                    },
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        self.state = InitializeVisitorState::DontWarn;
 +                    },
 +                    _ => (),
 +                }
 +            }
 +
 +            walk_expr(self, expr);
 +        } else if !self.past_loop && is_loop(expr) {
 +            self.state = InitializeVisitorState::DontWarn;
 +        } else if is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +}
 +
 +fn is_loop(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Loop(..))
 +}
 +
 +fn is_conditional(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..))
 +}
 +
 +#[derive(PartialEq, Eq)]
 +pub(super) enum Nesting {
 +    Unknown,     // no nesting detected yet
 +    RuledOut,    // the iterator is initialized or assigned within scope
 +    LookFurther, // no nesting detected, no further walk required
 +}
 +
 +use self::Nesting::{LookFurther, RuledOut, Unknown};
 +
 +pub(super) struct LoopNestVisitor {
 +    pub(super) hir_id: HirId,
 +    pub(super) iterator: HirId,
 +    pub(super) nesting: Nesting,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        if stmt.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +        } else if self.nesting == Unknown {
 +            walk_stmt(self, stmt);
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if expr.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +            return;
 +        }
 +        match expr.kind {
 +            ExprKind::Assign(path, _, _) | ExprKind::AssignOp(_, path, _) => {
 +                if path_to_local_id(path, self.iterator) {
 +                    self.nesting = RuledOut;
 +                }
 +            },
 +            _ => walk_expr(self, expr),
 +        }
 +    }
 +
 +    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if let PatKind::Binding(_, id, ..) = pat.kind {
 +            if id == self.iterator {
 +                self.nesting = RuledOut;
 +                return;
 +            }
 +        }
 +        walk_pat(self, pat);
 +    }
 +}
 +
 +/// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 +/// actual `Iterator` that the loop uses.
 +pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
 +    let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
 +        implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
 +    });
 +    if impls_iterator {
 +        format!(
 +            "{}",
 +            sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +        )
 +    } else {
 +        // (&x).into_iter() ==> x.iter()
 +        // (&mut x).into_iter() ==> x.iter_mut()
 +        let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
 +        match &arg_ty.kind() {
 +            ty::Ref(_, inner_ty, mutbl) if has_iter_method(cx, *inner_ty).is_some() => {
 +                let method_name = match mutbl {
 +                    Mutability::Mut => "iter_mut",
 +                    Mutability::Not => "iter",
 +                };
 +                let caller = match &arg.kind {
 +                    ExprKind::AddrOf(BorrowKind::Ref, _, arg_inner) => arg_inner,
 +                    _ => arg,
 +                };
 +                format!(
 +                    "{}.{method_name}()",
 +                    sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(),
 +                )
 +            },
 +            _ => format!(
 +                "{}.into_iter()",
 +                sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +            ),
 +        }
 +    }
 +}
index b8ed9b9ec18f718b0cc56160b0966a9e0cf220a5,0000000000000000000000000000000000000000..4277455a3a21c8e096e0c36e588724d065372d99
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,94 @@@
- use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg};
 +use crate::rustc_lint::LintContext;
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 +use clippy_utils::source::snippet_with_applicability;
++use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `assert!` is simpler than `if`-then-`panic!`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let sad_people: Vec<&str> = vec![];
 +    /// if !sad_people.is_empty() {
 +    ///     panic!("there are sad people: {:?}", sad_people);
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let sad_people: Vec<&str> = vec![];
 +    /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
 +    /// ```
 +    #[clippy::version = "1.57.0"]
 +    pub MANUAL_ASSERT,
 +    pedantic,
 +    "`panic!` and only a `panic!` in `if`-then statement"
 +}
 +
 +declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ManualAssert {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
 +        if_chain! {
 +            if let ExprKind::If(cond, then, None) = expr.kind;
 +            if !matches!(cond.kind, ExprKind::Let(_));
 +            if !expr.span.from_expansion();
 +            let then = peel_blocks_with_stmt(then);
 +            if let Some(macro_call) = root_macro_call(then.span);
 +            if cx.tcx.item_name(macro_call.def_id) == sym::panic;
 +            if !cx.tcx.sess.source_map().is_multiline(cond.span);
 +            if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
++            // Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
++            // shuffles the condition around.
++            // Should this have a config value?
++            if !is_else_clause(cx.tcx, expr);
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
 +                let cond = cond.peel_drop_temps();
 +                let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
 +                if !comments.is_empty() {
 +                    comments += "\n";
 +                }
 +                let (cond, not) = match cond.kind {
 +                    ExprKind::Unary(UnOp::Not, e) => (e, ""),
 +                    _ => (cond, "!"),
 +                };
 +                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
 +                span_lint_and_then(
 +                    cx,
 +                    MANUAL_ASSERT,
 +                    expr.span,
 +                    "only a `panic!` in `if`-then statement",
 +                    |diag| {
 +                        // comments can be noisy, do not show them to the user
 +                        if !comments.is_empty() {
 +                            diag.tool_only_span_suggestion(
 +                                        expr.span.shrink_to_lo(),
 +                                        "add comments back",
 +                                        comments,
 +                                        applicability);
 +                        }
 +                        diag.span_suggestion(
 +                                    expr.span,
 +                                    "try instead",
 +                                    sugg,
 +                                    applicability);
 +                                     }
 +
 +                );
 +            }
 +        }
 +    }
 +}
index 5ab049d8d133fd34629227da15fbfef84c255915,0000000000000000000000000000000000000000..d9ef7dffa020dbbd6d24715a35129fa72f88bcf2
mode 100644,000000..100644
--- /dev/null
@@@ -1,155 -1,0 +1,176 @@@
- use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
 +use clippy_utils::msrvs::{self, Msrv};
- use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
++use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
++use rustc_ast::ast::RangeLimits;
 +use rustc_ast::LitKind::{Byte, Char};
 +use rustc_errors::Applicability;
- use rustc_span::{def_id::DefId, sym};
++use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
-         let Some(macro_call) = root_macro_call(expr.span) else { return };
-         if is_matches_macro(cx, macro_call.def_id) {
++use rustc_span::{def_id::DefId, sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Suggests to use dedicated built-in methods,
 +    /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the built-in functions is more readable and makes it
 +    /// clear that it's not a specific subset of characters, but all
 +    /// ASCII (lowercase|uppercase|digit) characters.
 +    /// ### Example
 +    /// ```rust
 +    /// fn main() {
 +    ///     assert!(matches!('x', 'a'..='z'));
 +    ///     assert!(matches!(b'X', b'A'..=b'Z'));
 +    ///     assert!(matches!('2', '0'..='9'));
 +    ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
++    ///
++    ///     ('0'..='9').contains(&'0');
++    ///     ('a'..='z').contains(&'a');
++    ///     ('A'..='Z').contains(&'A');
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn main() {
 +    ///     assert!('x'.is_ascii_lowercase());
 +    ///     assert!(b'X'.is_ascii_uppercase());
 +    ///     assert!('2'.is_ascii_digit());
 +    ///     assert!('x'.is_ascii_alphabetic());
++    ///
++    ///     '0'.is_ascii_digit();
++    ///     'a'.is_ascii_lowercase();
++    ///     'A'.is_ascii_uppercase();
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.66.0"]
 +    pub MANUAL_IS_ASCII_CHECK,
 +    style,
 +    "use dedicated method to check ascii range"
 +}
 +impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
 +
 +pub struct ManualIsAsciiCheck {
 +    msrv: Msrv,
 +}
 +
 +impl ManualIsAsciiCheck {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq)]
 +enum CharRange {
 +    /// 'a'..='z' | b'a'..=b'z'
 +    LowerChar,
 +    /// 'A'..='Z' | b'A'..=b'Z'
 +    UpperChar,
 +    /// AsciiLower | AsciiUpper
 +    FullChar,
 +    /// '0..=9'
 +    Digit,
 +    Otherwise,
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) {
 +            return;
 +        }
 +
 +        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) {
 +            return;
 +        }
 +
-                 if let Some(sugg) = match range {
-                     CharRange::UpperChar => Some("is_ascii_uppercase"),
-                     CharRange::LowerChar => Some("is_ascii_lowercase"),
-                     CharRange::FullChar => Some("is_ascii_alphabetic"),
-                     CharRange::Digit => Some("is_ascii_digit"),
-                     CharRange::Otherwise => None,
-                 } {
-                     let default_snip = "..";
-                     // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
-                     // macro span, so we check applicability manually by comparing `recv` is not default.
-                     let recv = snippet(cx, recv.span, default_snip);
-                     let applicability = if recv == default_snip {
-                         Applicability::HasPlaceholders
-                     } else {
-                         Applicability::MachineApplicable
-                     };
-                     span_lint_and_sugg(
-                         cx,
-                         MANUAL_IS_ASCII_CHECK,
-                         macro_call.span,
-                         "manual check for common ascii range",
-                         "try",
-                         format!("{recv}.{sugg}()"),
-                         applicability,
-                     );
-                 }
++        if let Some(macro_call) = root_macro_call(expr.span)
++            && is_matches_macro(cx, macro_call.def_id) {
 +            if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
 +                let range = check_pat(&arm.pat.kind);
++                check_is_ascii(cx, macro_call.span, recv, &range);
++            }
++        } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
++            && path.ident.name == sym!(contains)
++            && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
++            = higher::Range::hir(receiver) {
++            let range = check_range(start, end);
++            if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
++                check_is_ascii(cx, expr.span, e, &range);
++            } else {
++                check_is_ascii(cx, expr.span, arg, &range);
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
++fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
++    if let Some(sugg) = match range {
++        CharRange::UpperChar => Some("is_ascii_uppercase"),
++        CharRange::LowerChar => Some("is_ascii_lowercase"),
++        CharRange::FullChar => Some("is_ascii_alphabetic"),
++        CharRange::Digit => Some("is_ascii_digit"),
++        CharRange::Otherwise => None,
++    } {
++        let default_snip = "..";
++        // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
++        // macro span, so we check applicability manually by comparing `recv` is not default.
++        let recv = snippet(cx, recv.span, default_snip);
++
++        let applicability = if recv == default_snip {
++            Applicability::HasPlaceholders
++        } else {
++            Applicability::MachineApplicable
++        };
++
++        span_lint_and_sugg(
++            cx,
++            MANUAL_IS_ASCII_CHECK,
++            span,
++            "manual check for common ascii range",
++            "try",
++            format!("{recv}.{sugg}()"),
++            applicability,
++        );
++    }
++}
++
 +fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
 +    match pat_kind {
 +        PatKind::Or(pats) => {
 +            let ranges = pats.iter().map(|p| check_pat(&p.kind)).collect::<Vec<_>>();
 +
 +            if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
 +                CharRange::FullChar
 +            } else {
 +                CharRange::Otherwise
 +            }
 +        },
 +        PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end),
 +        _ => CharRange::Otherwise,
 +    }
 +}
 +
 +fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
 +    if let ExprKind::Lit(start_lit) = &start.kind
 +        && let ExprKind::Lit(end_lit) = &end.kind {
 +        match (&start_lit.node, &end_lit.node) {
 +            (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
 +            (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
 +            (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
 +            _ => CharRange::Otherwise,
 +        }
 +    } else {
 +        CharRange::Otherwise
 +    }
 +}
 +
 +fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
 +    if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
 +        return sym::matches_macro == name;
 +    }
 +
 +    false
 +}
index 874d36ca9f4e378704019c8ae971c046c68d898c,0000000000000000000000000000000000000000..9c6f8b43c078fbc77abd20dd5e7b374c47b6ffad
mode 100644,000000..100644
--- /dev/null
@@@ -1,295 -1,0 +1,300 @@@
-             let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::higher::IfLetOrMatch;
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::peel_blocks;
 +use clippy_utils::source::snippet_with_context;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::visitors::{for_each_expr, Descend};
 +use if_chain::if_chain;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::sym;
 +use rustc_span::Span;
 +use serde::Deserialize;
 +use std::ops::ControlFlow;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Warn of cases where `let...else` could be used
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// `let...else` provides a standard construct for this pattern
 +    /// that people can easily recognize. It's also more compact.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```rust
 +    /// # let w = Some(0);
 +    /// let v = if let Some(v) = w { v } else { return };
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// # #![feature(let_else)]
 +    /// # fn main () {
 +    /// # let w = Some(0);
 +    /// let Some(v) = w else { return };
 +    /// # }
 +    /// ```
 +    #[clippy::version = "1.67.0"]
 +    pub MANUAL_LET_ELSE,
 +    pedantic,
 +    "manual implementation of a let...else statement"
 +}
 +
 +pub struct ManualLetElse {
 +    msrv: Msrv,
 +    matches_behaviour: MatchLintBehaviour,
 +}
 +
 +impl ManualLetElse {
 +    #[must_use]
 +    pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
 +        Self {
 +            msrv,
 +            matches_behaviour,
 +        }
 +    }
 +}
 +
 +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;
 +            }
 +        };
 +
 +        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);
 +                }
 +            },
 +            IfLetOrMatch::Match(match_expr, arms, source) => {
 +                if self.matches_behaviour == MatchLintBehaviour::Never {
 +                    return;
 +                }
 +                if source != MatchSource::Normal {
 +                    return;
 +                }
 +                // Any other number than two arms doesn't (neccessarily)
 +                // have a trivial mapping to let else.
 +                if arms.len() != 2 {
 +                    return;
 +                }
 +                // Guards don't give us an easy mapping either
 +                if arms.iter().any(|arm| arm.guard.is_some()) {
 +                    return;
 +                }
 +                let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
 +                let diverging_arm_opt = arms
 +                    .iter()
 +                    .enumerate()
 +                    .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
 +                let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
 +                let pat_arm = &arms[1 - idx];
 +                if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
 +                    return;
 +                }
 +
 +                emit_manual_let_else(cx, stmt.span, match_expr, 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<'_>) {
 +    span_lint_and_then(
 +        cx,
 +        MANUAL_LET_ELSE,
 +        span,
 +        "this could be rewritten as `let...else`",
 +        |diag| {
 +            // This is far from perfect, for example there needs to be:
 +            // * mut additions for the bindings
 +            // * renamings of the bindings
 +            // * 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);
 +
 +            let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
 +                sn_else.into_owned()
 +            } else {
 +                format!("{{ {sn_else} }}")
 +            };
++            let sn_bl = if matches!(pat.kind, PatKind::Or(..)) {
++                format!("({sn_pat})")
++            } else {
++                sn_pat.into_owned()
++            };
++            let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
 +            diag.span_suggestion(span, "consider writing", sugg, app);
 +        },
 +    );
 +}
 +
 +fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
 +    fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
 +        if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
 +            return ty.is_never();
 +        }
 +        false
 +    }
 +    // We can't just call is_never on expr and be done, because the type system
 +    // sometimes coerces the ! type to something different before we can get
 +    // our hands on it. So instead, we do a manual search. We do fall back to
 +    // is_never in some places when there is no better alternative.
 +    for_each_expr(expr, |ex| {
 +        match ex.kind {
 +            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
 +            ExprKind::Call(call, _) => {
 +                if is_never(cx, ex) || is_never(cx, call) {
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(Descend::Yes)
 +            },
 +            ExprKind::MethodCall(..) => {
 +                if is_never(cx, ex) {
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(Descend::Yes)
 +            },
 +            ExprKind::If(if_expr, if_then, if_else) => {
 +                let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
 +                let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
 +                if diverges {
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(Descend::No)
 +            },
 +            ExprKind::Match(match_expr, match_arms, _) => {
 +                let diverges = expr_diverges(cx, match_expr)
 +                    || match_arms.iter().all(|arm| {
 +                        let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
 +                        guard_diverges || expr_diverges(cx, arm.body)
 +                    });
 +                if diverges {
 +                    return ControlFlow::Break(());
 +                }
 +                ControlFlow::Continue(Descend::No)
 +            },
 +
 +            // Don't continue into loops or labeled blocks, as they are breakable,
 +            // and we'd have to start checking labels.
 +            ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
 +
 +            // Default: descend
 +            _ => ControlFlow::Continue(Descend::Yes),
 +        }
 +    })
 +    .is_some()
 +}
 +
 +fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
 +    // Check whether the pattern contains any bindings, as the
 +    // binding might potentially be used in the body.
 +    // TODO: only look for *used* bindings.
 +    let mut has_bindings = false;
 +    pat.each_binding_or_first(&mut |_, _, _, _| has_bindings = true);
 +    if has_bindings {
 +        return false;
 +    }
 +
 +    // If we shouldn't check the types, exit early.
 +    if !check_types {
 +        return true;
 +    }
 +
 +    // Check whether any possibly "unknown" patterns are included,
 +    // because users might not know which values some enum has.
 +    // Well-known enums are excepted, as we assume people know them.
 +    // We do a deep check, to be able to disallow Err(En::Foo(_))
 +    // for usage of the En::Foo variant, as we disallow En::Foo(_),
 +    // but we allow Err(_).
 +    let typeck_results = cx.typeck_results();
 +    let mut has_disallowed = false;
 +    pat.walk_always(|pat| {
 +        // Only do the check if the type is "spelled out" in the pattern
 +        if !matches!(
 +            pat.kind,
 +            PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
 +        ) {
 +            return;
 +        };
 +        let ty = typeck_results.pat_ty(pat);
 +        // Option and Result are allowed, everything else isn't.
 +        if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
 +            has_disallowed = true;
 +        }
 +    });
 +    !has_disallowed
 +}
 +
 +/// Checks if the passed block is a simple identity referring to bindings created by the pattern
 +fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
 +    // We support patterns with multiple bindings and tuples, like:
 +    //   let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
 +    let peeled = peel_blocks(expr);
 +    let paths = match peeled.kind {
 +        ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
 +        ExprKind::Path(_) => std::slice::from_ref(peeled),
 +        _ => return false,
 +    };
 +    let mut pat_bindings = FxHashSet::default();
 +    pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
 +        pat_bindings.insert(ident);
 +    });
 +    if pat_bindings.len() < paths.len() {
 +        return false;
 +    }
 +    for path in paths {
 +        if_chain! {
 +            if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
 +            if let [path_seg] = path.segments;
 +            then {
 +                if !pat_bindings.remove(&path_seg.ident) {
 +                    return false;
 +                }
 +            } else {
 +                return false;
 +            }
 +        }
 +    }
 +    true
 +}
 +
 +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
 +pub enum MatchLintBehaviour {
 +    AllTypes,
 +    WellKnownTypes,
 +    Never,
 +}
index c1e6c82487dc54d79b5e86185541108c149af35e,0000000000000000000000000000000000000000..72cdb9c17361676240c5d767cd34a67db9164dbd
mode 100644,000000..100644
--- /dev/null
@@@ -1,224 -1,0 +1,225 @@@
-             && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 +use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::ExprKind::Assign;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::sym;
 +
 +const ACCEPTABLE_METHODS: [&[&str]; 4] = [
 +    &paths::HASHSET_ITER,
 +    &paths::BTREESET_ITER,
 +    &paths::SLICE_INTO,
 +    &paths::VEC_DEQUE_ITER,
 +];
 +const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 6] = [
 +    (sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)),
 +    (sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)),
 +    (sym::HashSet, Some(msrvs::HASH_SET_RETAIN)),
 +    (sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)),
 +    (sym::Vec, None),
 +    (sym::VecDeque, None),
 +];
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for code to be replaced by `.retain()`.
 +    /// ### Why is this bad?
 +    /// `.retain()` is simpler and avoids needless allocation.
 +    /// ### Example
 +    /// ```rust
 +    /// let mut vec = vec![0, 1, 2];
 +    /// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
 +    /// vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut vec = vec![0, 1, 2];
 +    /// vec.retain(|x| x % 2 == 0);
 +    /// ```
 +    #[clippy::version = "1.64.0"]
 +    pub MANUAL_RETAIN,
 +    perf,
 +    "`retain()` is simpler and the same functionalitys"
 +}
 +
 +pub struct ManualRetain {
 +    msrv: Msrv,
 +}
 +
 +impl ManualRetain {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ManualRetain {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if let Some(parent_expr) = get_parent_expr(cx, expr)
 +            && let Assign(left_expr, collect_expr, _) = &parent_expr.kind
 +            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
 +            && seg.args.is_none()
 +            && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
 +            && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
++            && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
++        {
 +            check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
 +            check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
 +            check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +fn check_into_iter(
 +    cx: &LateContext<'_>,
 +    parent_expr: &hir::Expr<'_>,
 +    left_expr: &hir::Expr<'_>,
 +    target_expr: &hir::Expr<'_>,
 +    msrv: &Msrv,
 +) {
 +    if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
 +        && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
 +        && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
 +        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
 +        && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
 +        && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
 +        && match_acceptable_type(cx, left_expr, msrv)
 +        && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
 +        suggest(cx, parent_expr, left_expr, target_expr);
 +    }
 +}
 +
 +fn check_iter(
 +    cx: &LateContext<'_>,
 +    parent_expr: &hir::Expr<'_>,
 +    left_expr: &hir::Expr<'_>,
 +    target_expr: &hir::Expr<'_>,
 +    msrv: &Msrv,
 +) {
 +    if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
 +        && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
 +        && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
 +            || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
 +        && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
 +        && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
 +        && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
 +        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
 +        && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
 +        && match_acceptable_def_path(cx, iter_expr_def_id)
 +        && match_acceptable_type(cx, left_expr, msrv)
 +        && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
 +        suggest(cx, parent_expr, left_expr, filter_expr);
 +    }
 +}
 +
 +fn check_to_owned(
 +    cx: &LateContext<'_>,
 +    parent_expr: &hir::Expr<'_>,
 +    left_expr: &hir::Expr<'_>,
 +    target_expr: &hir::Expr<'_>,
 +    msrv: &Msrv,
 +) {
 +    if msrv.meets(msrvs::STRING_RETAIN)
 +        && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
 +        && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
 +        && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
 +        && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
 +        && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
 +        && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
 +        && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
 +        && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
 +        && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
 +        && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
 +        && is_type_lang_item(cx, ty, hir::LangItem::String)
 +        && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) {
 +        suggest(cx, parent_expr, left_expr, filter_expr);
 +    }
 +}
 +
 +fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
 +    if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
 +        && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
 +        && let filter_body = cx.tcx.hir().body(body)
 +        && let [filter_params] = filter_body.params
 +        && let Some(sugg) = match filter_params.pat.kind {
 +            hir::PatKind::Binding(_, _, filter_param_ident, None) => {
 +                Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
 +            },
 +            hir::PatKind::Tuple([key_pat, value_pat], _) => {
 +                make_sugg(cx, key_pat, value_pat, left_expr, filter_body)
 +            },
 +            hir::PatKind::Ref(pat, _) => {
 +                match pat.kind {
 +                    hir::PatKind::Binding(_, _, filter_param_ident, None) => {
 +                        Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
 +                    },
 +                    _ => None
 +                }
 +            },
 +            _ => None
 +        } {
 +        span_lint_and_sugg(
 +            cx,
 +            MANUAL_RETAIN,
 +            parent_expr.span,
 +            "this expression can be written more simply using `.retain()`",
 +            "consider calling `.retain()` instead",
 +            sugg,
 +            Applicability::MachineApplicable
 +        );
 +    }
 +}
 +
 +fn make_sugg(
 +    cx: &LateContext<'_>,
 +    key_pat: &rustc_hir::Pat<'_>,
 +    value_pat: &rustc_hir::Pat<'_>,
 +    left_expr: &hir::Expr<'_>,
 +    filter_body: &hir::Body<'_>,
 +) -> Option<String> {
 +    match (&key_pat.kind, &value_pat.kind) {
 +        (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Binding(_, _, value_param_ident, None)) => {
 +            Some(format!(
 +                "{}.retain(|{key_param_ident}, &mut {value_param_ident}| {})",
 +                snippet(cx, left_expr.span, ".."),
 +                snippet(cx, filter_body.value.span, "..")
 +            ))
 +        },
 +        (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Wild) => Some(format!(
 +            "{}.retain(|{key_param_ident}, _| {})",
 +            snippet(cx, left_expr.span, ".."),
 +            snippet(cx, filter_body.value.span, "..")
 +        )),
 +        (hir::PatKind::Wild, hir::PatKind::Binding(_, _, value_param_ident, None)) => Some(format!(
 +            "{}.retain(|_, &mut {value_param_ident}| {})",
 +            snippet(cx, left_expr.span, ".."),
 +            snippet(cx, filter_body.value.span, "..")
 +        )),
 +        _ => None,
 +    }
 +}
 +
 +fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
 +    ACCEPTABLE_METHODS
 +        .iter()
 +        .any(|&method| match_def_path(cx, collect_def_id, method))
 +}
 +
 +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
 +    let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
 +    ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
 +        is_type_diagnostic_item(cx, expr_ty, *ty)
 +            && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
 +    })
 +}
index 429cdc1918d79d7c03d1d5b24fe1bff04c8e7afb,0000000000000000000000000000000000000000..06ecbce4e70e940bed5d941b41be29198817ef6c
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,60 @@@
- use clippy_utils::ty::peel_mid_ty_refs;
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_context;
++use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
 +use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +use super::IMPLICIT_CLONE;
 +
 +pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
 +    if_chain! {
 +        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
 +        if is_clone_like(cx, method_name, method_def_id);
 +        let return_type = cx.typeck_results().expr_ty(expr);
 +        let input_type = cx.typeck_results().expr_ty(recv);
 +        let (input_type, ref_count) = peel_mid_ty_refs(input_type);
 +        if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
 +        if return_type == input_type;
++        if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
++        if implements_trait(cx, return_type, clone_trait, &[]);
 +        then {
 +            let mut app = Applicability::MachineApplicable;
 +            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
 +            span_lint_and_sugg(
 +                cx,
 +                IMPLICIT_CLONE,
 +                expr.span,
 +                &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
 +                "consider using",
 +                if ref_count > 1 {
 +                    format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1))
 +                } else {
 +                    format!("{recv_snip}.clone()")
 +                },
 +                app,
 +            );
 +        }
 +    }
 +}
 +
 +/// Returns true if the named method can be used to clone the receiver.
 +/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
 +/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
 +/// `is_to_owned_like` in `unnecessary_to_owned.rs`.
 +pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
 +    match method_name {
 +        "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
 +        "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
 +        "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
 +        "to_vec" => cx
 +            .tcx
 +            .impl_of_method(method_def_id)
 +            .filter(|&impl_did| cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none())
 +            .is_some(),
 +        _ => false,
 +    }
 +}
index d2913680cbb742a11db2439aa668aff4d0a979c0,0000000000000000000000000000000000000000..561e4336593b047ed5f071e89c18f5ec6c82c69e
mode 100644,000000..100644
--- /dev/null
@@@ -1,3996 -1,0 +1,3999 @@@
-     #[clippy::version = "1.65.0"]
 +mod bind_instead_of_map;
 +mod bytecount;
 +mod bytes_count_to_len;
 +mod bytes_nth;
 +mod case_sensitive_file_extension_comparisons;
 +mod chars_cmp;
 +mod chars_cmp_with_unwrap;
 +mod chars_last_cmp;
 +mod chars_last_cmp_with_unwrap;
 +mod chars_next_cmp;
 +mod chars_next_cmp_with_unwrap;
 +mod clone_on_copy;
 +mod clone_on_ref_ptr;
 +mod cloned_instead_of_copied;
 +mod collapsible_str_replace;
 +mod err_expect;
 +mod expect_fun_call;
 +mod expect_used;
 +mod extend_with_drain;
 +mod filetype_is_file;
 +mod filter_map;
 +mod filter_map_identity;
 +mod filter_map_next;
 +mod filter_next;
 +mod flat_map_identity;
 +mod flat_map_option;
 +mod from_iter_instead_of_collect;
 +mod get_first;
 +mod get_last_with_len;
 +mod get_unwrap;
 +mod implicit_clone;
 +mod inefficient_to_string;
 +mod inspect_for_each;
 +mod into_iter_on_ref;
 +mod is_digit_ascii_radix;
 +mod iter_cloned_collect;
 +mod iter_count;
 +mod iter_kv_map;
 +mod iter_next_slice;
 +mod iter_nth;
 +mod iter_nth_zero;
 +mod iter_on_single_or_empty_collections;
 +mod iter_overeager_cloned;
 +mod iter_skip_next;
 +mod iter_with_drain;
 +mod iterator_step_by_zero;
 +mod manual_ok_or;
 +mod manual_saturating_arithmetic;
 +mod manual_str_repeat;
 +mod map_clone;
 +mod map_collect_result_unit;
 +mod map_err_ignore;
 +mod map_flatten;
 +mod map_identity;
 +mod map_unwrap_or;
 +mod mut_mutex_lock;
 +mod needless_collect;
 +mod needless_option_as_deref;
 +mod needless_option_take;
 +mod no_effect_replace;
 +mod obfuscated_if_else;
 +mod ok_expect;
 +mod open_options;
 +mod option_as_ref_deref;
 +mod option_map_or_none;
 +mod option_map_unwrap_or;
 +mod or_fun_call;
 +mod or_then_unwrap;
 +mod path_buf_push_overwrite;
 +mod range_zip_with_len;
 +mod repeat_once;
 +mod search_is_some;
 +mod seek_from_current;
 +mod seek_to_start_instead_of_rewind;
 +mod single_char_add_str;
 +mod single_char_insert_string;
 +mod single_char_pattern;
 +mod single_char_push_string;
 +mod skip_while_next;
 +mod stable_sort_primitive;
 +mod str_splitn;
 +mod string_extend_chars;
 +mod suspicious_map;
 +mod suspicious_splitn;
 +mod suspicious_to_owned;
 +mod uninit_assumed_init;
 +mod unit_hash;
 +mod unnecessary_filter_map;
 +mod unnecessary_fold;
 +mod unnecessary_iter_cloned;
 +mod unnecessary_join;
 +mod unnecessary_lazy_eval;
 +mod unnecessary_sort_by;
 +mod unnecessary_to_owned;
 +mod unwrap_or_else_default;
 +mod unwrap_used;
 +mod useless_asref;
 +mod utils;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wrong_self_convention;
 +mod zst_offset;
 +
 +use bind_instead_of_map::BindInsteadOfMap;
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
 +use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
 +use rustc_hir_analysis::hir_ty_to_ty;
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, TraitRef, Ty};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `cloned()` on an `Iterator` or `Option` where
 +    /// `copied()` could be used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `copied()` is better because it guarantees that the type being cloned
 +    /// implements `Copy`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1, 2, 3].iter().cloned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// [1, 2, 3].iter().copied();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub CLONED_INSTEAD_OF_COPIED,
 +    pedantic,
 +    "used `cloned` where `copied` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for consecutive calls to `str::replace` (2 or more)
 +    /// that can be collapsed into a single call.
 +    ///
 +    /// ### Why is this bad?
 +    /// Consecutive `str::replace` calls scan the string multiple times
 +    /// with repetitive code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let hello = "hesuo worpd"
 +    ///     .replace('s', "l")
 +    ///     .replace("u", "l")
 +    ///     .replace('p', "l");
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
 +    /// ```
 +    #[clippy::version = "1.65.0"]
 +    pub COLLAPSIBLE_STR_REPLACE,
 +    perf,
 +    "collapse consecutive calls to str::replace (2 or more) into a single call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's often inefficient to clone all elements of an iterator, when eventually, only some
 +    /// of them will be consumed.
 +    ///
 +    /// ### Known Problems
 +    /// This `lint` removes the side of effect of cloning items in the iterator.
 +    /// A code that relies on that side-effect could fail.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let vec = vec!["string".to_string()];
 +    /// vec.iter().cloned().take(10);
 +    /// vec.iter().cloned().last();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let vec = vec!["string".to_string()];
 +    /// vec.iter().take(10).cloned();
 +    /// vec.iter().last().cloned();
 +    /// ```
 +    #[clippy::version = "1.60.0"]
 +    pub ITER_OVEREAGER_CLONED,
 +    perf,
 +    "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
 +    /// used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// When applicable, `filter_map()` is more clear since it shows that
 +    /// `Option` is used to produce 0 or 1 items.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub FLAT_MAP_OPTION,
 +    pedantic,
 +    "used `flat_map` where `filter_map` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is better to handle the `None` or `Err` case,
 +    /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
 +    /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// `result.unwrap()` will let the thread panic on `Err` values.
 +    /// Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// Even if you want to panic on errors, not all `Error`s implement good
 +    /// messages on display. Therefore, it may be beneficial to look at the places
 +    /// where they may get displayed. Activate this lint to do just that.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// option.unwrap();
 +    /// result.unwrap();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// option.expect("more helpful message");
 +    /// result.expect("more helpful message");
 +    /// ```
 +    ///
 +    /// If [expect_used](#expect_used) is enabled, instead:
 +    /// ```rust,ignore
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// option?;
 +    ///
 +    /// // or
 +    ///
 +    /// result?;
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub UNWRAP_USED,
 +    restriction,
 +    "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// Usually it is better to handle the `None` or `Err` case.
 +    /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
 +    /// this lint is `Allow` by default.
 +    ///
 +    /// `result.expect()` will let the thread panic on `Err`
 +    /// values. Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// ### Examples
 +    /// ```rust,ignore
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// option.expect("one");
 +    /// result.expect("one");
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// option?;
 +    ///
 +    /// // or
 +    ///
 +    /// result?;
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub EXPECT_USED,
 +    restriction,
 +    "using `.expect()` on `Result` or `Option`, which might be better handled"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods that should live in a trait
 +    /// implementation of a `std` trait (see [llogiq's blog
 +    /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
 +    /// information) instead of an inherent implementation.
 +    ///
 +    /// ### Why is this bad?
 +    /// Implementing the traits improve ergonomics for users of
 +    /// the code, often with very little cost. Also people seeing a `mul(...)`
 +    /// method
 +    /// may expect `*` to work equally, so you should have good reason to disappoint
 +    /// them.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn add(&self, other: &X) -> X {
 +    ///         // ..
 +    /// # X
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHOULD_IMPLEMENT_TRAIT,
 +    style,
 +    "defining a method that should be implementing a std trait"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods with certain name prefixes and which
 +    /// doesn't match how self is taken. The actual rules are:
 +    ///
 +    /// |Prefix |Postfix     |`self` taken                   | `self` type  |
 +    /// |-------|------------|-------------------------------|--------------|
 +    /// |`as_`  | none       |`&self` or `&mut self`         | any          |
 +    /// |`from_`| none       | none                          | any          |
 +    /// |`into_`| none       |`self`                         | any          |
 +    /// |`is_`  | none       |`&mut self` or `&self` or none | any          |
 +    /// |`to_`  | `_mut`     |`&mut self`                    | any          |
 +    /// |`to_`  | not `_mut` |`self`                         | `Copy`       |
 +    /// |`to_`  | not `_mut` |`&self`                        | not `Copy`   |
 +    ///
 +    /// Note: Clippy doesn't trigger methods with `to_` prefix in:
 +    /// - Traits definition.
 +    /// Clippy can not tell if a type that implements a trait is `Copy` or not.
 +    /// - Traits implementation, when `&self` is taken.
 +    /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
 +    /// (see e.g. the `std::string::ToString` trait).
 +    ///
 +    /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
 +    ///
 +    /// Please find more info here:
 +    /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
 +    ///
 +    /// ### Why is this bad?
 +    /// Consistency breeds readability. If you follow the
 +    /// conventions, your users won't be surprised that they, e.g., need to supply a
 +    /// mutable reference to a `as_..` function.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct X;
 +    /// impl X {
 +    ///     fn as_str(self) -> &'static str {
 +    ///         // ..
 +    /// # ""
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub WRONG_SELF_CONVENTION,
 +    style,
 +    "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `ok().expect(..)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Because you usually call `expect()` on the `Result`
 +    /// directly to get a better error message.
 +    ///
 +    /// ### Known problems
 +    /// The error type needs to implement `Debug`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = Ok::<_, ()>(());
 +    /// x.ok().expect("why did I do this again?");
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = Ok::<_, ()>(());
 +    /// x.expect("why did I do this again?");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OK_EXPECT,
 +    style,
 +    "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.err().expect()` calls on the `Result` type.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
 +    ///
 +    /// ### Example
 +    /// ```should_panic
 +    /// let x: Result<u32, &str> = Ok(10);
 +    /// x.err().expect("Testing err().expect()");
 +    /// ```
 +    /// Use instead:
 +    /// ```should_panic
 +    /// let x: Result<u32, &str> = Ok(10);
 +    /// x.expect_err("Testing expect_err");
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub ERR_EXPECT,
 +    style,
 +    r#"using `.err().expect("")` when `.expect_err("")` can be used"#
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
 +    /// `Result` values.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written as `_.unwrap_or_default`, which is
 +    /// simpler and more concise.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let x = Some(1);
 +    /// x.unwrap_or_else(Default::default);
 +    /// x.unwrap_or_else(u32::default);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = Some(1);
 +    /// x.unwrap_or_default();
 +    /// ```
 +    #[clippy::version = "1.56.0"]
 +    pub UNWRAP_OR_ELSE_DEFAULT,
 +    style,
 +    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
 +    /// `result.map(_).unwrap_or_else(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written more concisely (resp.) as
 +    /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
 +    ///
 +    /// ### Known problems
 +    /// The order of the arguments is not in execution order
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// # fn some_function(foo: ()) -> usize { 1 }
 +    /// option.map(|a| a + 1).unwrap_or(0);
 +    /// result.map(|a| a + 1).unwrap_or_else(some_function);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let option = Some(1);
 +    /// # let result: Result<usize, ()> = Ok(1);
 +    /// # fn some_function(foo: ()) -> usize { 1 }
 +    /// option.map_or(0, |a| a + 1);
 +    /// result.map_or_else(some_function, |a| a + 1);
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub MAP_UNWRAP_OR,
 +    pedantic,
 +    "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map_or(None, _)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.and_then(_)`.
 +    ///
 +    /// ### Known problems
 +    /// The order of the arguments is not in execution order.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    /// opt.map_or(None, |a| Some(a + 1));
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    /// opt.and_then(|a| Some(a + 1));
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OPTION_MAP_OR_NONE,
 +    style,
 +    "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map_or(None, Some)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.ok()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let r: Result<u32, &str> = Ok(1);
 +    /// assert_eq!(Some(1), r.map_or(None, Some));
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let r: Result<u32, &str> = Ok(1);
 +    /// assert_eq!(Some(1), r.ok());
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub RESULT_MAP_OR_INTO_OPTION,
 +    style,
 +    "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
 +    /// `_.or_else(|x| Err(y))`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.map(|x| y)` or `_.map_err(|x| y)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn opt() -> Option<&'static str> { Some("42") }
 +    /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
 +    /// let _ = opt().and_then(|s| Some(s.len()));
 +    /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
 +    /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// # fn opt() -> Option<&'static str> { Some("42") }
 +    /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
 +    /// let _ = opt().map(|s| s.len());
 +    /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
 +    /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub BIND_INSTEAD_OF_MAP,
 +    complexity,
 +    "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter(_).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().filter(|x| **x == 0).next();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FILTER_NEXT,
 +    complexity,
 +    "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.skip_while(condition).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find(!condition)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().skip_while(|x| **x == 0).next();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().find(|x| **x != 0);
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub SKIP_WHILE_NEXT,
 +    complexity,
 +    "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![vec![1]];
 +    /// let opt = Some(5);
 +    ///
 +    /// vec.iter().map(|x| x.iter()).flatten();
 +    /// opt.map(|x| Some(x * 2)).flatten();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let vec = vec![vec![1]];
 +    /// # let opt = Some(5);
 +    /// vec.iter().flat_map(|x| x.iter());
 +    /// opt.and_then(|x| Some(x * 2));
 +    /// ```
 +    #[clippy::version = "1.31.0"]
 +    pub MAP_FLATTEN,
 +    complexity,
 +    "using combinations of `flatten` and `map` which can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter(_).map(_)` that can be written more simply
 +    /// as `filter_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `filter` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// ```rust
 +    /// # #![allow(unused)]
 +    /// (0_i32..10)
 +    ///     .filter(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # #[allow(unused)]
 +    /// (0_i32..10).filter_map(|n| n.checked_add(1));
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub MANUAL_FILTER_MAP,
 +    complexity,
 +    "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.find(_).map(_)` that can be written more simply
 +    /// as `find_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `find` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .find(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// (0_i32..10).find_map(|n| n.checked_add(1));
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub MANUAL_FIND_MAP,
 +    complexity,
 +    "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter_map(_).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find_map(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
 +    /// ```
 +    /// Can be written as
 +    ///
 +    /// ```rust
 +    ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
 +    /// ```
 +    #[clippy::version = "1.36.0"]
 +    pub FILTER_MAP_NEXT,
 +    pedantic,
 +    "using combination of `filter_map` and `next` which can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `flat_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flat_map(|x| x);
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub FLAT_MAP_IDENTITY,
 +    complexity,
 +    "call to `flat_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for an iterator or string search (such as `find()`,
 +    /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as:
 +    /// * `_.any(_)`, or `_.contains(_)` for `is_some()`,
 +    /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # #![allow(unused)]
 +    /// let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0).is_some();
 +    ///
 +    /// "hello world".find("world").is_none();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().any(|x| *x == 0);
 +    ///
 +    /// # #[allow(unused)]
 +    /// !"hello world".contains("world");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SEARCH_IS_SOME,
 +    complexity,
 +    "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.chars().next()` on a `str` to check
 +    /// if it starts with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.starts_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.chars().next() == Some('_') {};
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.starts_with('_') {};
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHARS_NEXT_CMP,
 +    style,
 +    "using `.chars().next()` to check if a string starts with a char"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
 +    /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
 +    /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
 +    /// etc. instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// The function will always be called. This is only bad if it allocates or
 +    /// does some non-trivial amount of work.
 +    ///
 +    /// ### Known problems
 +    /// If the function has side-effects, not calling it will change the
 +    /// semantic of the program, but you shouldn't rely on that.
 +    ///
 +    /// The lint also cannot figure out whether the function you call is
 +    /// actually expensive to call or not.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or(String::from("empty"));
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or_else(|| String::from("empty"));
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OR_FUN_CALL,
 +    nursery,
 +    "using any `*or` method with a function call, which suggests `*or_else`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.or(…).unwrap()` calls to Options and Results.
 +    ///
 +    /// ### Why is this bad?
 +    /// You should use `.unwrap_or(…)` instead for clarity.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let fallback = "fallback";
 +    /// // Result
 +    /// # type Error = &'static str;
 +    /// # let result: Result<&str, Error> = Err("error");
 +    /// let value = result.or::<Error>(Ok(fallback)).unwrap();
 +    ///
 +    /// // Option
 +    /// # let option: Option<&str> = None;
 +    /// let value = option.or(Some(fallback)).unwrap();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let fallback = "fallback";
 +    /// // Result
 +    /// # let result: Result<&str, &str> = Err("error");
 +    /// let value = result.unwrap_or(fallback);
 +    ///
 +    /// // Option
 +    /// # let option: Option<&str> = None;
 +    /// let value = option.unwrap_or(fallback);
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub OR_THEN_UNWRAP,
 +    complexity,
 +    "checks for `.or(…).unwrap()` calls to Options and Results."
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
 +    /// etc., and suggests to use `unwrap_or_else` instead
 +    ///
 +    /// ### Why is this bad?
 +    /// The function will always be called.
 +    ///
 +    /// ### Known problems
 +    /// If the function has side-effects, not calling it will
 +    /// change the semantics of the program, but you shouldn't rely on that anyway.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// # let err_code = "418";
 +    /// # let err_msg = "I'm a teapot";
 +    /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
 +    ///
 +    /// // or
 +    ///
 +    /// # let foo = Some(String::new());
 +    /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// # let err_code = "418";
 +    /// # let err_msg = "I'm a teapot";
 +    /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EXPECT_FUN_CALL,
 +    perf,
 +    "using any `expect` method with a function call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.clone()` on a `Copy` type.
 +    ///
 +    /// ### Why is this bad?
 +    /// The only reason `Copy` types implement `Clone` is for
 +    /// generics, not for using the `clone` method on a concrete type.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// 42u64.clone();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CLONE_ON_COPY,
 +    complexity,
 +    "using `clone` on a `Copy` type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.clone()` on a ref-counted pointer,
 +    /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
 +    /// function syntax instead (e.g., `Rc::clone(foo)`).
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling '.clone()' on an Rc, Arc, or Weak
 +    /// can obscure the fact that only the pointer is being cloned, not the underlying
 +    /// data.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::rc::Rc;
 +    /// let x = Rc::new(1);
 +    ///
 +    /// x.clone();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::rc::Rc;
 +    /// # let x = Rc::new(1);
 +    /// Rc::clone(&x);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CLONE_ON_REF_PTR,
 +    restriction,
 +    "using 'clone' on a ref-counted pointer"
 +}
 +
 +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`).
 +    ///
 +    /// ### Why is this bad?
 +    /// This bypasses the specialized implementation of
 +    /// `ToString` and instead goes through the more expensive string formatting
 +    /// facilities.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Generic implementation for `T: Display` is used (slow)
 +    /// ["foo", "bar"].iter().map(|s| s.to_string());
 +    ///
 +    /// // OK, the specialized impl is used
 +    /// ["foo", "bar"].iter().map(|&s| s.to_string());
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub INEFFICIENT_TO_STRING,
 +    pedantic,
 +    "using `to_string` on `&&T` where `T: ToString`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `new` not returning a type that contains `Self`.
 +    ///
 +    /// ### Why is this bad?
 +    /// As a convention, `new` methods are used to make a new
 +    /// instance of a type.
 +    ///
 +    /// ### Example
 +    /// In an impl block:
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct NotAFoo;
 +    /// impl Foo {
 +    ///     fn new() -> NotAFoo {
 +    /// # NotAFoo
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// struct Bar(Foo);
 +    /// impl Foo {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new() -> Bar {
 +    /// # Bar(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct FooError;
 +    /// impl Foo {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Result<Foo, FooError> {
 +    /// # Ok(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Or in a trait definition:
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new();
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Self;
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEW_RET_NO_SELF,
 +    style,
 +    "not returning type containing `Self` in a `new` method"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for string methods that receive a single-character
 +    /// `str` as an argument, e.g., `_.split("x")`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Performing these methods using a `char` is faster than
 +    /// using a `str`.
 +    ///
 +    /// ### Known problems
 +    /// Does not catch multi-byte unicode characters.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// _.split("x");
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// _.split('x');
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SINGLE_CHAR_PATTERN,
 +    perf,
 +    "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calling `.step_by(0)` on iterators which panics.
 +    ///
 +    /// ### Why is this bad?
 +    /// This very much looks like an oversight. Use `panic!()` instead if you
 +    /// actually intend to panic.
 +    ///
 +    /// ### Example
 +    /// ```rust,should_panic
 +    /// for x in (0..100).step_by(0) {
 +    ///     //..
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITERATOR_STEP_BY_ZERO,
 +    correctness,
 +    "using `Iterator::step_by(0)`, which will panic at runtime"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for indirect collection of populated `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// `Option` is like a collection of 0-1 things, so `flatten`
 +    /// automatically does this without suspicious-looking `unwrap` calls.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().flatten();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub OPTION_FILTER_MAP,
 +    complexity,
 +    "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `iter.nth(0)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `iter.next()` is equivalent to
 +    /// `iter.nth(0)`, as they both consume the next element,
 +    ///  but is more readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().nth(0);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().next();
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub ITER_NTH_ZERO,
 +    style,
 +    "replace `iter.nth(0)` with `iter.next()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.iter().nth()` (and the related
 +    /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.get()` and `.get_mut()` are more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.get(3);
 +    /// let bad_slice = &some_vec[..].get(3);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_NTH,
 +    perf,
 +    "using `.iter().nth()` on a standard library type with O(1) element access"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.skip(x).next()` on iterators.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.nth(x)` is cleaner
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().skip(3).next();
 +    /// let bad_slice = &some_vec[..].iter().skip(3).next();
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_SKIP_NEXT,
 +    style,
 +    "using `.skip(x).next()` on an iterator"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.into_iter()` is simpler with better performance.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// let mut foo = vec![0, 1, 2, 3];
 +    /// let bar: HashSet<usize> = foo.drain(..).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// let foo = vec![0, 1, 2, 3];
 +    /// let bar: HashSet<usize> = foo.into_iter().collect();
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub ITER_WITH_DRAIN,
 +    nursery,
 +    "replace `.drain(..)` with `.into_iter()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for using `x.get(x.len() - 1)` instead of
 +    /// `x.last()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `x.last()` is easier to read and has the same
 +    /// result.
 +    ///
 +    /// Note that using `x[x.len() - 1]` is semantically different from
 +    /// `x.last()`.  Indexing into the array will panic on out-of-bounds
 +    /// accesses, while `x.get()` and `x.last()` will return `None`.
 +    ///
 +    /// There is another lint (get_unwrap) that covers the case of using
 +    /// `x.get(index).unwrap()` instead of `x[index]`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = vec![2, 3, 5];
 +    /// let last_element = x.get(x.len() - 1);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = vec![2, 3, 5];
 +    /// let last_element = x.last();
 +    /// ```
 +    #[clippy::version = "1.37.0"]
 +    pub GET_LAST_WITH_LEN,
 +    complexity,
 +    "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.get().unwrap()` (or
 +    /// `.get_mut().unwrap`) on a standard library type which implements `Index`
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the Index trait (`[]`) is more clear and more
 +    /// concise.
 +    ///
 +    /// ### Known problems
 +    /// Not a replacement for error handling: Using either
 +    /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
 +    /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
 +    /// temporary placeholder for dealing with the `Option` type, then this does
 +    /// not mitigate the need for error handling. If there is a chance that `.get()`
 +    /// will be `None` in your program, then it is advisable that the `None` case
 +    /// is handled in a future refactor instead of using `.unwrap()` or the Index
 +    /// trait.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut some_vec = vec![0, 1, 2, 3];
 +    /// let last = some_vec.get(3).unwrap();
 +    /// *some_vec.get_mut(0).unwrap() = 1;
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let mut some_vec = vec![0, 1, 2, 3];
 +    /// let last = some_vec[3];
 +    /// some_vec[0] = 1;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub GET_UNWRAP,
 +    restriction,
 +    "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for occurrences where one vector gets extended instead of append
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `append` instead of `extend` is more concise and faster
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut a = vec![1, 2, 3];
 +    /// let mut b = vec![4, 5, 6];
 +    ///
 +    /// a.extend(b.drain(..));
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut a = vec![1, 2, 3];
 +    /// let mut b = vec![4, 5, 6];
 +    ///
 +    /// a.append(&mut b);
 +    /// ```
 +    #[clippy::version = "1.55.0"]
 +    pub EXTEND_WITH_DRAIN,
 +    perf,
 +    "using vec.append(&mut vec) to move the full range of a vector to another"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.extend(s.chars())` where s is a
 +    /// `&str` or `String`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.push_str(s)` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.extend(abc.chars());
 +    /// s.extend(def.chars());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.push_str(abc);
 +    /// s.push_str(&def);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_EXTEND_CHARS,
 +    style,
 +    "using `x.extend(s.chars())` where s is a `&str` or `String`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.cloned().collect()` on slice to
 +    /// create a `Vec`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.to_vec()` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s[..].iter().cloned().collect();
 +    /// ```
 +    /// The better use would be:
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s.to_vec();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_CLONED_COLLECT,
 +    style,
 +    "using `.cloned().collect()` on slice to create a `Vec`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.chars().last()` or
 +    /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.ends_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let name = "_";
 +    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let name = "_";
 +    /// name.ends_with('_') || name.ends_with('-');
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHARS_LAST_CMP,
 +    style,
 +    "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.as_ref()` or `.as_mut()` where the
 +    /// types before and after the call are the same.
 +    ///
 +    /// ### Why is this bad?
 +    /// The call is unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x.as_ref());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USELESS_ASREF,
 +    complexity,
 +    "using `as_ref` where the types before and after the call are the same"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for using `fold` when a more succinct alternative exists.
 +    /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
 +    /// `sum` or `product`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # #[allow(unused)]
 +    /// (0..3).fold(false, |acc, x| acc || x > 2);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// (0..3).any(|x| x > 2);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNNECESSARY_FOLD,
 +    style,
 +    "using `fold` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `filter_map` calls that could be replaced by `filter` or `map`.
 +    /// More specifically it checks if the closure provided is only performing one of the
 +    /// filter or map operations and suggests the appropriate option.
 +    ///
 +    /// ### Why is this bad?
 +    /// Complexity. The intent is also clearer if only a single
 +    /// operation is being performed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
 +    ///
 +    /// // As there is no transformation of the argument this could be written as:
 +    /// let _ = (0..3).filter(|&x| x > 2);
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// let _ = (0..4).filter_map(|x| Some(x + 1));
 +    ///
 +    /// // As there is no conditional check on the argument this could be written as:
 +    /// let _ = (0..4).map(|x| x + 1);
 +    /// ```
 +    #[clippy::version = "1.31.0"]
 +    pub UNNECESSARY_FILTER_MAP,
 +    complexity,
 +    "using `filter_map` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `find_map` calls that could be replaced by `find` or `map`. More
 +    /// specifically it checks if the closure provided is only performing one of the
 +    /// find or map operations and suggests the appropriate option.
 +    ///
 +    /// ### Why is this bad?
 +    /// Complexity. The intent is also clearer if only a single
 +    /// operation is being performed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
 +    ///
 +    /// // As there is no transformation of the argument this could be written as:
 +    /// let _ = (0..3).find(|&x| x > 2);
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// let _ = (0..4).find_map(|x| Some(x + 1));
 +    ///
 +    /// // As there is no conditional check on the argument this could be written as:
 +    /// let _ = (0..4).map(|x| x + 1).next();
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub UNNECESSARY_FIND_MAP,
 +    complexity,
 +    "using `find_map` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `into_iter` calls on references which should be replaced by `iter`
 +    /// or `iter_mut`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability. Calling `into_iter` on a reference will not move out its
 +    /// content into the resulting iterator, which is confusing. It is better just call `iter` or
 +    /// `iter_mut` directly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![3, 4, 5];
 +    /// (&vec).into_iter();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let vec = vec![3, 4, 5];
 +    /// (&vec).iter();
 +    /// ```
 +    #[clippy::version = "1.32.0"]
 +    pub INTO_ITER_ON_REF,
 +    style,
 +    "using `.into_iter()` on a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `map` followed by a `count`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It looks suspicious. Maybe `map` was confused with `filter`.
 +    /// If the `map` call is intentional, this should be rewritten
 +    /// using `inspect`. Or, if you intend to drive the iterator to
 +    /// completion, you can just use `for_each` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).map(|x| x + 2).count();
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub SUSPICIOUS_MAP,
 +    suspicious,
 +    "suspicious usage of map"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `MaybeUninit::uninit().assume_init()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// For most types, this is undefined behavior.
 +    ///
 +    /// ### Known problems
 +    /// For now, we accept empty tuples and tuples / arrays
 +    /// of `MaybeUninit`. There may be other types that allow uninitialized
 +    /// data, but those are not yet rigorously defined.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Beware the UB
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
 +    /// ```
 +    ///
 +    /// Note that the following is OK:
 +    ///
 +    /// ```rust
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: [MaybeUninit<bool>; 5] = unsafe {
 +    ///     MaybeUninit::uninit().assume_init()
 +    /// };
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub UNINIT_ASSUMED_INIT,
 +    correctness,
 +    "`MaybeUninit::uninit().assume_init()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be written simply with `saturating_add/sub` methods.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let y: u32 = 0;
 +    /// # let x: u32 = 100;
 +    /// let add = x.checked_add(y).unwrap_or(u32::MAX);
 +    /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
 +    /// ```
 +    ///
 +    /// can be written using dedicated methods for saturating addition/subtraction as:
 +    ///
 +    /// ```rust
 +    /// # let y: u32 = 0;
 +    /// # let x: u32 = 100;
 +    /// let add = x.saturating_add(y);
 +    /// let sub = x.saturating_sub(y);
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub MANUAL_SATURATING_ARITHMETIC,
 +    style,
 +    "`.checked_add/sub(x).unwrap_or(MAX/MIN)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
 +    /// zero-sized types
 +    ///
 +    /// ### Why is this bad?
 +    /// This is a no-op, and likely unintended
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// unsafe { (&() as *const ()).offset(1) };
 +    /// ```
 +    #[clippy::version = "1.41.0"]
 +    pub ZST_OFFSET,
 +    correctness,
 +    "Check for offset calculations on raw pointers to zero-sized types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `FileType::is_file()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// When people testing a file type with `FileType::is_file`
 +    /// they are testing whether a path is something they can get bytes from. But
 +    /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
 +    /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # || {
 +    /// let metadata = std::fs::metadata("foo.txt")?;
 +    /// let filetype = metadata.file_type();
 +    ///
 +    /// if filetype.is_file() {
 +    ///     // read file
 +    /// }
 +    /// # Ok::<_, std::io::Error>(())
 +    /// # };
 +    /// ```
 +    ///
 +    /// should be written as:
 +    ///
 +    /// ```rust
 +    /// # || {
 +    /// let metadata = std::fs::metadata("foo.txt")?;
 +    /// let filetype = metadata.file_type();
 +    ///
 +    /// if !filetype.is_dir() {
 +    ///     // read file
 +    /// }
 +    /// # Ok::<_, std::io::Error>(())
 +    /// # };
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub FILETYPE_IS_FILE,
 +    restriction,
 +    "`FileType::is_file` is not recommended to test for readable file type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.as_deref()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_ref().map(String::as_str)
 +    /// # ;
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_deref()
 +    /// # ;
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub OPTION_AS_REF_DEREF,
 +    complexity,
 +    "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `iter().next()` on a Slice or an Array
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be shortened into `.get()`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a[2..].iter().next();
 +    /// b.iter().next();
 +    /// ```
 +    /// should be written as:
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a.get(2);
 +    /// b.get(0);
 +    /// ```
 +    #[clippy::version = "1.46.0"]
 +    pub ITER_NEXT_SLICE,
 +    style,
 +    "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns when using `push_str`/`insert_str` with a single-character string literal
 +    /// where `push`/`insert` with a `char` would work fine.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's less clear that we are pushing a single character.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let mut string = String::new();
 +    /// string.insert_str(0, "R");
 +    /// string.push_str("R");
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let mut string = String::new();
 +    /// string.insert(0, 'R');
 +    /// string.push('R');
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub SINGLE_CHAR_ADD_STR,
 +    style,
 +    "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// As the counterpart to `or_fun_call`, this lint looks for unnecessary
 +    /// lazily evaluated closures on `Option` and `Result`.
 +    ///
 +    /// This lint suggests changing the following functions, when eager evaluation results in
 +    /// simpler code:
 +    ///  - `unwrap_or_else` to `unwrap_or`
 +    ///  - `and_then` to `and`
 +    ///  - `or_else` to `or`
 +    ///  - `get_or_insert_with` to `get_or_insert`
 +    ///  - `ok_or_else` to `ok_or`
 +    ///
 +    /// ### Why is this bad?
 +    /// Using eager evaluation is shorter and simpler in some cases.
 +    ///
 +    /// ### Known problems
 +    /// It is possible, but not recommended for `Deref` and `Index` to have
 +    /// side effects. Eagerly evaluating them can change the semantics of the program.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or_else(|| 42);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or(42);
 +    /// ```
 +    #[clippy::version = "1.48.0"]
 +    pub UNNECESSARY_LAZY_EVALUATIONS,
 +    style,
 +    "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map(_).collect::<Result<(), _>()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `try_for_each` instead is more readable and idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// (0..3).try_for_each(|t| Err(t));
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub MAP_COLLECT_RESULT_UNIT,
 +    style,
 +    "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `from_iter()` function calls on types that implement the `FromIterator`
 +    /// trait.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is recommended style to use collect. See
 +    /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v = Vec::from_iter(five_fives);
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v: Vec<i32> = five_fives.collect();
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub FROM_ITER_INSTEAD_OF_COLLECT,
 +    pedantic,
 +    "use `.collect()` instead of `::from_iter()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `inspect().for_each()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is the same as performing the computation
 +    /// inside `inspect` at the beginning of the closure in `for_each`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .inspect(|&x| println!("inspect the number: {}", x))
 +    /// .for_each(|&x| {
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .for_each(|&x| {
 +    ///     println!("inspect the number: {}", x);
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub INSPECT_FOR_EACH,
 +    complexity,
 +    "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `filter_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.filter_map(|x| x);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub FILTER_MAP_IDENTITY,
 +    complexity,
 +    "call to `filter_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for instances of `map(f)` where `f` is the identity function.
 +    ///
 +    /// ### Why is this bad?
 +    /// It can be written more concisely without the call to `map`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub MAP_IDENTITY,
 +    complexity,
 +    "using iterator.map(|x| x)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.bytes().nth()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.as_bytes().get()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # #[allow(unused)]
 +    /// "Hello".bytes().nth(3);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # #[allow(unused)]
 +    /// "Hello".as_bytes().get(3);
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub BYTES_NTH,
 +    style,
 +    "replace `.bytes().nth()` with `.as_bytes().get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
 +    ///
 +    /// ### Why is this bad?
 +    /// These methods do the same thing as `_.clone()` but may be confusing as
 +    /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.to_vec();
 +    /// let c = a.to_owned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.clone();
 +    /// let c = a.clone();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub IMPLICIT_CLONE,
 +    pedantic,
 +    "implicitly cloning a value by invoking a function on its dereferenced type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.iter().count()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.len()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # #![allow(unused)]
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    ///
 +    /// some_vec.iter().count();
 +    /// &some_vec[..].iter().count();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    ///
 +    /// some_vec.len();
 +    /// &some_vec[..].len();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub ITER_COUNT,
 +    complexity,
 +    "replace `.iter().count()` with `.len()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
 +    /// itself, without taking ownership of the `Cow` contents (i.e.
 +    /// it's equivalent to calling `Cow::clone`).
 +    /// The similarly named `into_owned` method, on the other hand,
 +    /// clones the `Cow` contents, effectively turning any `Cow::Borrowed`
 +    /// into a `Cow::Owned`.
 +    ///
 +    /// Given the potential ambiguity, consider replacing `to_owned`
 +    /// with `clone` for better readability or, if getting a `Cow::Owned`
 +    /// was the original intent, using `into_owned` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::borrow::Cow;
 +    /// let s = "Hello world!";
 +    /// let cow = Cow::Borrowed(s);
 +    ///
 +    /// let data = cow.to_owned();
 +    /// assert!(matches!(data, Cow::Borrowed(_)))
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::borrow::Cow;
 +    /// let s = "Hello world!";
 +    /// let cow = Cow::Borrowed(s);
 +    ///
 +    /// let data = cow.clone();
 +    /// assert!(matches!(data, Cow::Borrowed(_)))
 +    /// ```
 +    /// or
 +    /// ```rust
 +    /// # use std::borrow::Cow;
 +    /// let s = "Hello world!";
 +    /// let cow = Cow::Borrowed(s);
 +    ///
 +    /// let _data: String = cow.into_owned();
 +    /// ```
 +    #[clippy::version = "1.65.0"]
 +    pub SUSPICIOUS_TO_OWNED,
 +    suspicious,
 +    "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to [`splitn`]
 +    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
 +    /// related functions with either zero or one splits.
 +    ///
 +    /// ### Why is this bad?
 +    /// These calls don't actually split the value and are
 +    /// likely to be intended as a different number.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let s = "";
 +    /// for x in s.splitn(1, ":") {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let s = "";
 +    /// for x in s.splitn(2, ":") {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub SUSPICIOUS_SPLITN,
 +    correctness,
 +    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for manual implementations of `str::repeat`
 +    ///
 +    /// ### Why is this bad?
 +    /// These are both harder to read, as well as less performant.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: String = std::iter::repeat('x').take(10).collect();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let x: String = "x".repeat(10);
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub MANUAL_STR_REPEAT,
 +    perf,
 +    "manual implementation of `str::repeat`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `str::splitn(2, _)`
 +    ///
 +    /// ### Why is this bad?
 +    /// `split_once` is both clearer in intent and slightly more efficient.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// let s = "key=value=add";
 +    /// let (key, value) = s.splitn(2, '=').next_tuple()?;
 +    /// let value = s.splitn(2, '=').nth(1)?;
 +    ///
 +    /// let mut parts = s.splitn(2, '=');
 +    /// let key = parts.next()?;
 +    /// let value = parts.next()?;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// let s = "key=value=add";
 +    /// let (key, value) = s.split_once('=')?;
 +    /// let value = s.split_once('=')?.1;
 +    ///
 +    /// let (key, value) = s.split_once('=')?;
 +    /// ```
 +    ///
 +    /// ### Limitations
 +    /// The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
 +    /// in two separate `let` statements that immediately follow the `splitn()`
 +    #[clippy::version = "1.57.0"]
 +    pub MANUAL_SPLIT_ONCE,
 +    complexity,
 +    "replace `.splitn(2, pat)` with `.split_once(pat)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages 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.
 +    /// ### Example
 +    /// ```rust
 +    /// let str = "key=value=add";
 +    /// let _ = str.splitn(3, '=').next().unwrap();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let str = "key=value=add";
 +    /// let _ = str.split('=').next().unwrap();
 +    /// ```
 +    #[clippy::version = "1.59.0"]
 +    pub NEEDLESS_SPLITN,
 +    complexity,
 +    "usages of `str::splitn` that can be replaced with `str::split`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
 +    /// and other `to_owned`-like functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// The unnecessary calls result in useless allocations.
 +    ///
 +    /// ### Known problems
 +    /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
 +    /// owned copy of a resource and the resource is later used mutably. See
 +    /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let path = std::path::Path::new("x");
 +    /// foo(&path.to_string_lossy().to_string());
 +    /// fn foo(s: &str) {}
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let path = std::path::Path::new("x");
 +    /// foo(&path.to_string_lossy());
 +    /// fn foo(s: &str) {}
 +    /// ```
 +    #[clippy::version = "1.59.0"]
 +    pub UNNECESSARY_TO_OWNED,
 +    perf,
 +    "unnecessary calls to `to_owned`-like functions"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.collect::<Vec<String>>().join("")` on iterators.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.collect::<String>()` is more concise and might be more performant
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vector = vec!["hello",  "world"];
 +    /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
 +    /// println!("{}", output);
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let vector = vec!["hello",  "world"];
 +    /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
 +    /// println!("{}", output);
 +    /// ```
 +    /// ### Known problems
 +    /// While `.collect::<String>()` is sometimes more performant, there are cases where
 +    /// using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
 +    /// will prevent loop unrolling and will result in a negative performance impact.
 +    ///
 +    /// Additionally, differences have been observed between aarch64 and x86_64 assembly output,
 +    /// with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
 +    #[clippy::version = "1.61.0"]
 +    pub UNNECESSARY_JOIN,
 +    pedantic,
 +    "using `.collect::<Vec<String>>().join(\"\")` on an iterator"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
 +    /// for example, `Option<&T>::as_deref()` returns the same type.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code and improving readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = Some(&1);
 +    /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = Some(&1);
 +    /// let b = a;
 +    /// ```
 +    #[clippy::version = "1.57.0"]
 +    pub NEEDLESS_OPTION_AS_DEREF,
 +    complexity,
 +    "no-op use of `deref` or `deref_mut` method to `Option`."
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
 +    /// can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
 +    /// [`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
 +    ///
 +    /// ### Why is this bad?
 +    /// `is_digit(..)` is slower and requires specifying the radix.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let c: char = '6';
 +    /// c.is_digit(10);
 +    /// c.is_digit(16);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let c: char = '6';
 +    /// c.is_ascii_digit();
 +    /// c.is_ascii_hexdigit();
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub IS_DIGIT_ASCII_RADIX,
 +    style,
 +    "use of `char::is_digit(..)` with literal radix of 10 or 16"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calling `take` function after `as_ref`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code. `take` writes `None` to its argument.
 +    /// In this case the modification is useless as it's a temporary that cannot be read from afterwards.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = Some(3);
 +    /// x.as_ref().take();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = Some(3);
 +    /// x.as_ref();
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub NEEDLESS_OPTION_TAKE,
 +    complexity,
 +    "using `.as_ref().take()` on a temporary value"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `replace` statements which have no effect.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's either a mistake or confusing.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// "1234".replace("12", "12");
 +    /// "1234".replacen("12", "12", 1);
 +    /// ```
 +    #[clippy::version = "1.63.0"]
 +    pub NO_EFFECT_REPLACE,
 +    suspicious,
 +    "replace with no effect"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `.then_some(..).unwrap_or(..)`
 +    ///
 +    /// ### Why is this bad?
 +    /// This can be written more clearly with `if .. else ..`
 +    ///
 +    /// ### Limitations
 +    /// This lint currently only looks for usages of
 +    /// `.then_some(..).unwrap_or(..)`, but will be expanded
 +    /// to account for similar patterns.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = true;
 +    /// x.then_some("a").unwrap_or("b");
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = true;
 +    /// if x { "a" } else { "b" };
 +    /// ```
 +    #[clippy::version = "1.64.0"]
 +    pub OBFUSCATED_IF_ELSE,
 +    style,
 +    "use of `.then_some(..).unwrap_or(..)` can be written \
 +    more clearly with `if .. else ..`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// It is simpler to use the once function from the standard library:
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```rust
 +    /// let a = [123].iter();
 +    /// let b = Some(123).into_iter();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::iter;
 +    /// let a = iter::once(&123);
 +    /// let b = iter::once(123);
 +    /// ```
 +    ///
 +    /// ### Known problems
 +    ///
 +    /// The type of the resulting iterator might become incompatible with its usage
 +    #[clippy::version = "1.65.0"]
 +    pub ITER_ON_SINGLE_ITEMS,
 +    nursery,
 +    "Iterator for array of length 1"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// It is simpler to use the empty function from the standard library:
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```rust
 +    /// use std::{slice, option};
 +    /// let a: slice::Iter<i32> = [].iter();
 +    /// let f: option::IntoIter<i32> = None.into_iter();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::iter;
 +    /// let a: iter::Empty<i32> = iter::empty();
 +    /// let b: iter::Empty<i32> = iter::empty();
 +    /// ```
 +    ///
 +    /// ### Known problems
 +    ///
 +    /// The type of the resulting iterator might become incompatible with its usage
 +    #[clippy::version = "1.65.0"]
 +    pub ITER_ON_EMPTY_COLLECTIONS,
 +    nursery,
 +    "Iterator for empty array"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for naive byte counts
 +    ///
 +    /// ### Why is this bad?
 +    /// The [`bytecount`](https://crates.io/crates/bytecount)
 +    /// crate has methods to count your bytes faster, especially for large slices.
 +    ///
 +    /// ### Known problems
 +    /// If you have predominantly small slices, the
 +    /// `bytecount::count(..)` method may actually be slower. However, if you can
 +    /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
 +    /// faster in those cases.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![1_u8];
 +    /// let count = vec.iter().filter(|x| **x == 0u8).count();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// # let vec = vec![1_u8];
 +    /// let count = bytecount::count(&vec, 0u8);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NAIVE_BYTECOUNT,
 +    pedantic,
 +    "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// It checks for `str::bytes().count()` and suggests replacing it with
 +    /// `str::len()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `str::bytes().count()` is longer and may not be as performant as using
 +    /// `str::len()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// "hello".bytes().count();
 +    /// String::from("hello").bytes().count();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// "hello".len();
 +    /// String::from("hello").len();
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub BYTES_COUNT_TO_LEN,
 +    complexity,
 +    "Using `bytes().count()` when `len()` performs the same functionality"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `ends_with` with possible file extensions
 +    /// and suggests to use a case-insensitive approach instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `ends_with` is case-sensitive and may not detect files with a valid extension.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn is_rust_file(filename: &str) -> bool {
 +    ///     filename.ends_with(".rs")
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn is_rust_file(filename: &str) -> bool {
 +    ///     let filename = std::path::Path::new(filename);
 +    ///     filename.extension()
 +    ///         .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
 +    pedantic,
 +    "Checks for calls to ends_with with case-sensitive file extensions"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for using `x.get(0)` instead of
 +    /// `x.first()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `x.first()` is easier to read and has the same
 +    /// result.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = vec![2, 3, 5];
 +    /// let first_element = x.get(0);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = vec![2, 3, 5];
 +    /// let first_element = x.first();
 +    /// ```
 +    #[clippy::version = "1.63.0"]
 +    pub GET_FIRST,
 +    style,
 +    "Using `x.get(0)` when `x.first()` is simpler"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Finds patterns that reimplement `Option::ok_or`.
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// Concise code helps focusing on behavior instead of boilerplate.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// let foo: Option<i32> = None;
 +    /// foo.map_or(Err("error"), |v| Ok(v));
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let foo: Option<i32> = None;
 +    /// foo.ok_or("error");
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub MANUAL_OK_OR,
 +    pedantic,
 +    "finds patterns that can be encoded more concisely with `Option::ok_or`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `map(|x| x.clone())` or
 +    /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
 +    /// and suggests `cloned()` or `copied()` instead
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = vec![42, 43];
 +    /// let y = x.iter();
 +    /// let z = y.map(|i| *i);
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// let x = vec![42, 43];
 +    /// let y = x.iter();
 +    /// let z = y.cloned();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MAP_CLONE,
 +    style,
 +    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for instances of `map_err(|_| Some::Enum)`
 +    ///
 +    /// ### Why is this bad?
 +    /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
 +    ///
 +    /// ### Example
 +    /// Before:
 +    /// ```rust
 +    /// use std::fmt;
 +    ///
 +    /// #[derive(Debug)]
 +    /// enum Error {
 +    ///     Indivisible,
 +    ///     Remainder(u8),
 +    /// }
 +    ///
 +    /// impl fmt::Display for Error {
 +    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +    ///         match self {
 +    ///             Error::Indivisible => write!(f, "could not divide input by three"),
 +    ///             Error::Remainder(remainder) => write!(
 +    ///                 f,
 +    ///                 "input is not divisible by three, remainder = {}",
 +    ///                 remainder
 +    ///             ),
 +    ///         }
 +    ///     }
 +    /// }
 +    ///
 +    /// impl std::error::Error for Error {}
 +    ///
 +    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
 +    ///     input
 +    ///         .parse::<i32>()
 +    ///         .map_err(|_| Error::Indivisible)
 +    ///         .map(|v| v % 3)
 +    ///         .and_then(|remainder| {
 +    ///             if remainder == 0 {
 +    ///                 Ok(())
 +    ///             } else {
 +    ///                 Err(Error::Remainder(remainder as u8))
 +    ///             }
 +    ///         })
 +    /// }
 +    ///  ```
 +    ///
 +    ///  After:
 +    ///  ```rust
 +    /// use std::{fmt, num::ParseIntError};
 +    ///
 +    /// #[derive(Debug)]
 +    /// enum Error {
 +    ///     Indivisible(ParseIntError),
 +    ///     Remainder(u8),
 +    /// }
 +    ///
 +    /// impl fmt::Display for Error {
 +    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +    ///         match self {
 +    ///             Error::Indivisible(_) => write!(f, "could not divide input by three"),
 +    ///             Error::Remainder(remainder) => write!(
 +    ///                 f,
 +    ///                 "input is not divisible by three, remainder = {}",
 +    ///                 remainder
 +    ///             ),
 +    ///         }
 +    ///     }
 +    /// }
 +    ///
 +    /// impl std::error::Error for Error {
 +    ///     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
 +    ///         match self {
 +    ///             Error::Indivisible(source) => Some(source),
 +    ///             _ => None,
 +    ///         }
 +    ///     }
 +    /// }
 +    ///
 +    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
 +    ///     input
 +    ///         .parse::<i32>()
 +    ///         .map_err(Error::Indivisible)
 +    ///         .map(|v| v % 3)
 +    ///         .and_then(|remainder| {
 +    ///             if remainder == 0 {
 +    ///                 Ok(())
 +    ///             } else {
 +    ///                 Err(Error::Remainder(remainder as u8))
 +    ///             }
 +    ///         })
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.48.0"]
 +    pub MAP_ERR_IGNORE,
 +    restriction,
 +    "`map_err` should not ignore the original error"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `&mut Mutex::lock` calls
 +    ///
 +    /// ### Why is this bad?
 +    /// `Mutex::lock` is less efficient than
 +    /// calling `Mutex::get_mut`. In addition you also have a statically
 +    /// guarantee that the mutex isn't locked, instead of just a runtime
 +    /// guarantee.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::sync::{Arc, Mutex};
 +    ///
 +    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
 +    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
 +    ///
 +    /// let mut value = value_mutex.lock().unwrap();
 +    /// *value += 1;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::sync::{Arc, Mutex};
 +    ///
 +    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
 +    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
 +    ///
 +    /// let value = value_mutex.get_mut().unwrap();
 +    /// *value += 1;
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub MUT_MUTEX_LOCK,
 +    style,
 +    "`&mut Mutex::lock` does unnecessary locking"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for duplicate open options as well as combinations
 +    /// that make no sense.
 +    ///
 +    /// ### Why is this bad?
 +    /// In the best case, the code will be harder to read than
 +    /// necessary. I don't know the worst case.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::fs::OpenOptions;
 +    ///
 +    /// OpenOptions::new().read(true).truncate(true);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NONSENSICAL_OPEN_OPTIONS,
 +    correctness,
 +    "nonsensical combination of options for opening a file"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
 +    /// calls on `PathBuf` that can cause overwrites.
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `push` with a root path at the start can overwrite the
 +    /// previous defined path.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::path::PathBuf;
 +    ///
 +    /// let mut x = PathBuf::from("/foo");
 +    /// x.push("/bar");
 +    /// assert_eq!(x, PathBuf::from("/bar"));
 +    /// ```
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// use std::path::PathBuf;
 +    ///
 +    /// let mut x = PathBuf::from("/foo");
 +    /// x.push("bar");
 +    /// assert_eq!(x, PathBuf::from("/foo/bar"));
 +    /// ```
 +    #[clippy::version = "1.36.0"]
 +    pub PATH_BUF_PUSH_OVERWRITE,
 +    nursery,
 +    "calling `push` with file system root on `PathBuf` can overwrite it"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for zipping a collection with the range of
 +    /// `0.._.len()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The code is better expressed with `.enumerate()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = vec![1];
 +    /// let _ = x.iter().zip(0..x.len());
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = vec![1];
 +    /// let _ = x.iter().enumerate();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub RANGE_ZIP_WITH_LEN,
 +    complexity,
 +    "zipping iterator with a range when `enumerate()` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
 +    /// - `.to_string()` for `str`
 +    /// - `.clone()` for `String`
 +    /// - `.to_vec()` for `slice`
 +    ///
 +    /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
 +    /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
 +    ///
 +    /// ### Why is this bad?
 +    /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
 +    /// the string is the intention behind this, `clone()` should be used.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").repeat(1);
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").clone();
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub REPEAT_ONCE,
 +    complexity,
 +    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// When sorting primitive values (integers, bools, chars, as well
 +    /// as arrays, slices, and tuples of such items), it is typically better to
 +    /// use an unstable sort than a stable sort.
 +    ///
 +    /// ### Why is this bad?
 +    /// Typically, using a stable sort consumes more memory and cpu cycles.
 +    /// Because values which compare equal are identical, preserving their
 +    /// relative order (the guarantee that a stable sort provides) means
 +    /// nothing, while the extra costs still apply.
 +    ///
 +    /// ### Known problems
 +    ///
 +    /// As pointed out in
 +    /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
 +    /// a stable sort can instead be significantly faster for certain scenarios
 +    /// (eg. when a sorted vector is extended with new data and resorted).
 +    ///
 +    /// For more information and benchmarking results, please refer to the
 +    /// issue linked above.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut vec = vec![2, 1, 3];
 +    /// vec.sort();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut vec = vec![2, 1, 3];
 +    /// vec.sort_unstable();
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub STABLE_SORT_PRIMITIVE,
 +    pedantic,
 +    "use of sort() when sort_unstable() is equivalent"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects `().hash(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::hash::Hash;
 +    /// # use std::collections::hash_map::DefaultHasher;
 +    /// # enum Foo { Empty, WithValue(u8) }
 +    /// # use Foo::*;
 +    /// # let mut state = DefaultHasher::new();
 +    /// # let my_enum = Foo::Empty;
 +    /// match my_enum {
 +    ///       Empty => ().hash(&mut state),
 +    ///       WithValue(x) => x.hash(&mut state),
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::hash::Hash;
 +    /// # use std::collections::hash_map::DefaultHasher;
 +    /// # enum Foo { Empty, WithValue(u8) }
 +    /// # use Foo::*;
 +    /// # let mut state = DefaultHasher::new();
 +    /// # let my_enum = Foo::Empty;
 +    /// match my_enum {
 +    ///       Empty => 0_u8.hash(&mut state),
 +    ///       WithValue(x) => x.hash(&mut state),
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub UNIT_HASH,
 +    correctness,
 +    "hashing a unit value, which does nothing"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects uses of `Vec::sort_by` passing in a closure
 +    /// which compares the two arguments, either directly or indirectly.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
 +    /// possible) than to use `Vec::sort_by` and a more complicated
 +    /// closure.
 +    ///
 +    /// ### Known problems
 +    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
 +    /// imported by a use statement, then it will need to be added manually.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct A;
 +    /// # impl A { fn foo(&self) {} }
 +    /// # let mut vec: Vec<A> = Vec::new();
 +    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # struct A;
 +    /// # impl A { fn foo(&self) {} }
 +    /// # let mut vec: Vec<A> = Vec::new();
 +    /// vec.sort_by_key(|a| a.foo());
 +    /// ```
 +    #[clippy::version = "1.46.0"]
 +    pub UNNECESSARY_SORT_BY,
 +    complexity,
 +    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Finds occurrences of `Vec::resize(0, an_int)`
 +    ///
 +    /// ### Why is this bad?
 +    /// This is probably an argument inversion mistake.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// vec!(1, 2, 3, 4, 5).clear()
 +    /// ```
 +    #[clippy::version = "1.46.0"]
 +    pub VEC_RESIZE_TO_ZERO,
 +    correctness,
 +    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use 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.
 +    /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// # use std::io::Read;
 +    /// # use std::fs::File;
 +    /// let mut f = File::open("foo.txt").unwrap();
 +    /// let mut bytes = Vec::new();
 +    /// f.read_to_end(&mut bytes).unwrap();
 +    /// ```
 +    /// Can be written more concisely as
 +    /// ```rust,no_run
 +    /// # use std::fs;
 +    /// let mut bytes = fs::read("foo.txt").unwrap();
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub VERBOSE_FILE_READS,
 +    restriction,
 +    "use of `File::read_to_end` or `File::read_to_string`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Checks for iterating a map (`HashMap` or `BTreeMap`) and
 +    /// ignoring either the keys or values.
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// Readability. There are `keys` and `values` methods that
 +    /// can be used to express that we only need the keys or the values.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```
 +    /// # use std::collections::HashMap;
 +    /// let map: HashMap<u32, u32> = HashMap::new();
 +    /// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```
 +    /// # use std::collections::HashMap;
 +    /// let map: HashMap<u32, u32> = HashMap::new();
 +    /// let values = map.values().collect::<Vec<_>>();
 +    /// ```
-                     if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
++    #[clippy::version = "1.66.0"]
 +    pub ITER_KV_MAP,
 +    complexity,
 +    "iterating on map using `iter` when `keys` or `values` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Checks an argument of `seek` method of `Seek` trait
 +    /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// Readability. Use dedicated method.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```rust,no_run
 +    /// use std::fs::File;
 +    /// use std::io::{self, Write, Seek, SeekFrom};
 +    ///
 +    /// fn main() -> io::Result<()> {
 +    ///     let mut f = File::create("foo.txt")?;
 +    ///     f.write_all(b"Hello")?;
 +    ///     eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
 +    ///
 +    ///     Ok(())
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust,no_run
 +    /// use std::fs::File;
 +    /// use std::io::{self, Write, Seek, SeekFrom};
 +    ///
 +    /// fn main() -> io::Result<()> {
 +    ///     let mut f = File::create("foo.txt")?;
 +    ///     f.write_all(b"Hello")?;
 +    ///     eprintln!("Written {} bytes", f.stream_position()?);
 +    ///
 +    ///     Ok(())
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.66.0"]
 +    pub SEEK_FROM_CURRENT,
 +    complexity,
 +    "use dedicated method for seek from current position"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///
 +    /// Checks for jumps to the start of a stream that implements `Seek`
 +    /// and uses the `seek` method providing `Start` as parameter.
 +    ///
 +    /// ### Why is this bad?
 +    ///
 +    /// Readability. There is a specific method that was implemented for
 +    /// this exact scenario.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::io;
 +    /// fn foo<T: io::Seek>(t: &mut T) {
 +    ///     t.seek(io::SeekFrom::Start(0));
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::io;
 +    /// fn foo<T: io::Seek>(t: &mut T) {
 +    ///     t.rewind();
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.66.0"]
 +    pub SEEK_TO_START_INSTEAD_OF_REWIND,
 +    complexity,
 +    "jumping to the start of stream using `seek` method"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for functions collecting an iterator when collect
 +    /// is not needed.
 +    ///
 +    /// ### Why is this bad?
 +    /// `collect` causes the allocation of a new data structure,
 +    /// when this allocation may not be needed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iterator = vec![1].into_iter();
 +    /// let len = iterator.clone().collect::<Vec<_>>().len();
 +    /// // should be
 +    /// let len = iterator.count();
 +    /// ```
 +    #[clippy::version = "1.30.0"]
 +    pub NEEDLESS_COLLECT,
 +    nursery,
 +    "collecting an iterator when collect is not needed"
 +}
 +
 +pub struct Methods {
 +    avoid_breaking_exported_api: bool,
 +    msrv: Msrv,
 +    allow_expect_in_tests: bool,
 +    allow_unwrap_in_tests: bool,
 +}
 +
 +impl Methods {
 +    #[must_use]
 +    pub fn new(
 +        avoid_breaking_exported_api: bool,
 +        msrv: Msrv,
 +        allow_expect_in_tests: bool,
 +        allow_unwrap_in_tests: bool,
 +    ) -> Self {
 +        Self {
 +            avoid_breaking_exported_api,
 +            msrv,
 +            allow_expect_in_tests,
 +            allow_unwrap_in_tests,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(Methods => [
 +    UNWRAP_USED,
 +    EXPECT_USED,
 +    SHOULD_IMPLEMENT_TRAIT,
 +    WRONG_SELF_CONVENTION,
 +    OK_EXPECT,
 +    UNWRAP_OR_ELSE_DEFAULT,
 +    MAP_UNWRAP_OR,
 +    RESULT_MAP_OR_INTO_OPTION,
 +    OPTION_MAP_OR_NONE,
 +    BIND_INSTEAD_OF_MAP,
 +    OR_FUN_CALL,
 +    OR_THEN_UNWRAP,
 +    EXPECT_FUN_CALL,
 +    CHARS_NEXT_CMP,
 +    CHARS_LAST_CMP,
 +    CLONE_ON_COPY,
 +    CLONE_ON_REF_PTR,
 +    CLONE_DOUBLE_REF,
 +    COLLAPSIBLE_STR_REPLACE,
 +    ITER_OVEREAGER_CLONED,
 +    CLONED_INSTEAD_OF_COPIED,
 +    FLAT_MAP_OPTION,
 +    INEFFICIENT_TO_STRING,
 +    NEW_RET_NO_SELF,
 +    SINGLE_CHAR_PATTERN,
 +    SINGLE_CHAR_ADD_STR,
 +    SEARCH_IS_SOME,
 +    FILTER_NEXT,
 +    SKIP_WHILE_NEXT,
 +    FILTER_MAP_IDENTITY,
 +    MAP_IDENTITY,
 +    MANUAL_FILTER_MAP,
 +    MANUAL_FIND_MAP,
 +    OPTION_FILTER_MAP,
 +    FILTER_MAP_NEXT,
 +    FLAT_MAP_IDENTITY,
 +    MAP_FLATTEN,
 +    ITERATOR_STEP_BY_ZERO,
 +    ITER_NEXT_SLICE,
 +    ITER_COUNT,
 +    ITER_NTH,
 +    ITER_NTH_ZERO,
 +    BYTES_NTH,
 +    ITER_SKIP_NEXT,
 +    GET_UNWRAP,
 +    GET_LAST_WITH_LEN,
 +    STRING_EXTEND_CHARS,
 +    ITER_CLONED_COLLECT,
 +    ITER_WITH_DRAIN,
 +    USELESS_ASREF,
 +    UNNECESSARY_FOLD,
 +    UNNECESSARY_FILTER_MAP,
 +    UNNECESSARY_FIND_MAP,
 +    INTO_ITER_ON_REF,
 +    SUSPICIOUS_MAP,
 +    UNINIT_ASSUMED_INIT,
 +    MANUAL_SATURATING_ARITHMETIC,
 +    ZST_OFFSET,
 +    FILETYPE_IS_FILE,
 +    OPTION_AS_REF_DEREF,
 +    UNNECESSARY_LAZY_EVALUATIONS,
 +    MAP_COLLECT_RESULT_UNIT,
 +    FROM_ITER_INSTEAD_OF_COLLECT,
 +    INSPECT_FOR_EACH,
 +    IMPLICIT_CLONE,
 +    SUSPICIOUS_TO_OWNED,
 +    SUSPICIOUS_SPLITN,
 +    MANUAL_STR_REPEAT,
 +    EXTEND_WITH_DRAIN,
 +    MANUAL_SPLIT_ONCE,
 +    NEEDLESS_SPLITN,
 +    UNNECESSARY_TO_OWNED,
 +    UNNECESSARY_JOIN,
 +    ERR_EXPECT,
 +    NEEDLESS_OPTION_AS_DEREF,
 +    IS_DIGIT_ASCII_RADIX,
 +    NEEDLESS_OPTION_TAKE,
 +    NO_EFFECT_REPLACE,
 +    OBFUSCATED_IF_ELSE,
 +    ITER_ON_SINGLE_ITEMS,
 +    ITER_ON_EMPTY_COLLECTIONS,
 +    NAIVE_BYTECOUNT,
 +    BYTES_COUNT_TO_LEN,
 +    CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
 +    GET_FIRST,
 +    MANUAL_OK_OR,
 +    MAP_CLONE,
 +    MAP_ERR_IGNORE,
 +    MUT_MUTEX_LOCK,
 +    NONSENSICAL_OPEN_OPTIONS,
 +    PATH_BUF_PUSH_OVERWRITE,
 +    RANGE_ZIP_WITH_LEN,
 +    REPEAT_ONCE,
 +    STABLE_SORT_PRIMITIVE,
 +    UNIT_HASH,
 +    UNNECESSARY_SORT_BY,
 +    VEC_RESIZE_TO_ZERO,
 +    VERBOSE_FILE_READS,
 +    ITER_KV_MAP,
 +    SEEK_FROM_CURRENT,
 +    SEEK_TO_START_INSTEAD_OF_REWIND,
 +    NEEDLESS_COLLECT,
 +]);
 +
 +/// Extracts a method call name, args, and `Span` of the method name.
 +fn method_call<'tcx>(
 +    recv: &'tcx hir::Expr<'tcx>,
 +) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
 +    if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
 +        if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
 +            let name = path.ident.name.as_str();
 +            return Some((name, receiver, args, path.ident.span, call_span));
 +        }
 +    }
 +    None
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Methods {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        self.check_methods(cx, expr);
 +
 +        match expr.kind {
 +            hir::ExprKind::Call(func, args) => {
 +                from_iter_instead_of_collect::check(cx, expr, args, func);
 +            },
 +            hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
 +                let method_span = method_call.ident.span;
 +                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
 +                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
 +                clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
 +                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
 +                inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
 +                single_char_add_str::check(cx, expr, receiver, args);
 +                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
 +                single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
 +                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
 +            },
 +            hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
 +                let mut info = BinaryExprInfo {
 +                    expr,
 +                    chain: lhs,
 +                    other: rhs,
 +                    eq: op.node == hir::BinOpKind::Eq,
 +                };
 +                lint_binary_expr_with_method_call(cx, &mut info);
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
 +        if in_external_macro(cx.sess(), impl_item.span) {
 +            return;
 +        }
 +        let name = impl_item.ident.name.as_str();
 +        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
 +        let item = cx.tcx.hir().expect_item(parent);
 +        let self_ty = cx.tcx.type_of(item.owner_id);
 +
 +        let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
 +        if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
 +            let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
 +            let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
 +            let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
 +            // if this impl block implements a trait, lint in trait definition instead
 +            if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
 +                // check missing trait implementations
 +                for method_config in &TRAIT_METHODS {
 +                    if name == method_config.method_name
 +                        && sig.decl.inputs.len() == method_config.param_count
 +                        && method_config.output_type.matches(&sig.decl.output)
 +                        // in case there is no first arg, since we already have checked the number of arguments
 +                        // it's should be always true
 +                        && first_arg_ty_opt.map_or(true, |first_arg_ty| method_config
 +                            .self_kind.matches(cx, self_ty, first_arg_ty)
 +                            )
 +                        && fn_header_equals(method_config.fn_header, sig.header)
 +                        && method_config.lifetime_param_cond(impl_item)
 +                    {
 +                        span_lint_and_help(
 +                            cx,
 +                            SHOULD_IMPLEMENT_TRAIT,
 +                            impl_item.span,
 +                            &format!(
 +                                "method `{}` can be confused for the standard trait method `{}::{}`",
 +                                method_config.method_name, method_config.trait_name, method_config.method_name
 +                            ),
 +                            None,
 +                            &format!(
 +                                "consider implementing the trait `{}` or choosing a less ambiguous method name",
 +                                method_config.trait_name
 +                            ),
 +                        );
 +                    }
 +                }
 +            }
 +
 +            if sig.decl.implicit_self.has_implicit_self()
 +                    && !(self.avoid_breaking_exported_api
 +                    && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
 +                    && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
 +                    && let Some(first_arg_ty) = first_arg_ty_opt
 +                {
 +                    wrong_self_convention::check(
 +                        cx,
 +                        name,
 +                        self_ty,
 +                        first_arg_ty,
 +                        first_arg.pat.span,
 +                        implements_trait,
 +                        false
 +                    );
 +                }
 +        }
 +
 +        // if this impl block implements a trait, lint in trait definition instead
 +        if implements_trait {
 +            return;
 +        }
 +
 +        if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
 +            let ret_ty = return_ty(cx, impl_item.hir_id());
 +
 +            if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
 +                return;
 +            }
 +
 +            if name == "new" && ret_ty != self_ty {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    impl_item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let TraitItemKind::Fn(ref sig, _) = item.kind;
 +            if sig.decl.implicit_self.has_implicit_self();
 +            if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
 +
 +            then {
 +                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();
 +                wrong_self_convention::check(
 +                    cx,
 +                    item.ident.name.as_str(),
 +                    self_ty,
 +                    first_arg_ty,
 +                    first_arg_span,
 +                    false,
 +                    true,
 +                );
 +            }
 +        }
 +
 +        if_chain! {
 +            if item.ident.name == sym::new;
 +            if let TraitItemKind::Fn(_, _) = item.kind;
 +            let ret_ty = return_ty(cx, item.hir_id());
 +            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
 +                .self_ty()
 +                .skip_binder();
 +            if !ret_ty.contains(self_ty);
 +
 +            then {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +impl Methods {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let Some((name, recv, args, span, call_span)) = method_call(expr) {
 +            match (name, args) {
 +                ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
 +                    zst_offset::check(cx, expr, recv);
 +                },
 +                ("and_then", [arg]) => {
 +                    let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
 +                    let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
 +                    if !biom_option_linted && !biom_result_linted {
 +                        unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
 +                    }
 +                },
 +                ("as_deref" | "as_deref_mut", []) => {
 +                    needless_option_as_deref::check(cx, expr, recv, name);
 +                },
 +                ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
 +                ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
 +                ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
 +                ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
 +                ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
 +                    needless_collect::check(cx, span, expr, recv, call_span);
 +                    match method_call(recv) {
 +                        Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
 +                            iter_cloned_collect::check(cx, name, expr, recv2);
 +                        },
 +                        Some(("map", m_recv, [m_arg], _, _)) => {
 +                            map_collect_result_unit::check(cx, expr, m_recv, m_arg);
 +                        },
 +                        Some(("take", take_self_arg, [take_arg], _, _)) => {
 +                            if self.msrv.meets(msrvs::STR_REPEAT) {
 +                                manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
 +                            }
 +                        },
 +                        _ => {},
 +                    }
 +                },
 +                ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
 +                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
 +                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
 +                        iter_count::check(cx, expr, recv2, name2);
 +                    },
 +                    Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
 +                    Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
 +                    Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
 +                    _ => {},
 +                },
 +                ("drain", [arg]) => {
 +                    iter_with_drain::check(cx, expr, recv, span, arg);
 +                },
 +                ("ends_with", [arg]) => {
 +                    if let ExprKind::MethodCall(.., span) = expr.kind {
 +                        case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
 +                    }
 +                },
 +                ("expect", [_]) => match method_call(recv) {
 +                    Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
 +                    Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
 +                    _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
 +                },
 +                ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
 +                ("extend", [arg]) => {
 +                    string_extend_chars::check(cx, expr, recv, arg);
 +                    extend_with_drain::check(cx, expr, recv, arg);
 +                },
 +                ("filter_map", [arg]) => {
 +                    unnecessary_filter_map::check(cx, expr, arg, name);
 +                    filter_map_identity::check(cx, expr, arg, span);
 +                },
 +                ("find_map", [arg]) => {
 +                    unnecessary_filter_map::check(cx, expr, arg, name);
 +                },
 +                ("flat_map", [arg]) => {
 +                    flat_map_identity::check(cx, expr, arg, span);
 +                    flat_map_option::check(cx, expr, arg, span);
 +                },
 +                ("flatten", []) => match method_call(recv) {
 +                    Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
 +                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
 +                    _ => {},
 +                },
 +                ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
 +                ("for_each", [_]) => {
 +                    if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
 +                        inspect_for_each::check(cx, expr, span2);
 +                    }
 +                },
 +                ("get", [arg]) => {
 +                    get_first::check(cx, expr, recv, arg);
 +                    get_last_with_len::check(cx, expr, recv, arg);
 +                },
 +                ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
 +                ("hash", [arg]) => {
 +                    unit_hash::check(cx, expr, recv, arg);
 +                },
 +                ("is_file", []) => filetype_is_file::check(cx, expr, recv),
 +                ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
 +                ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
 +                ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
 +                ("iter" | "iter_mut" | "into_iter", []) => {
 +                    iter_on_single_or_empty_collections::check(cx, expr, name, recv);
 +                },
 +                ("join", [join_arg]) => {
 +                    if let Some(("collect", _, _, span, _)) = method_call(recv) {
 +                        unnecessary_join::check(cx, expr, recv, join_arg, span);
 +                    }
 +                },
 +                ("last", []) | ("skip", [_]) => {
 +                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
 +                        if let ("cloned", []) = (name2, args2) {
 +                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
 +                        }
 +                    }
 +                },
 +                ("lock", []) => {
 +                    mut_mutex_lock::check(cx, expr, recv, span);
 +                },
 +                (name @ ("map" | "map_err"), [m_arg]) => {
 +                    if name == "map" {
 +                        map_clone::check(cx, expr, recv, m_arg, &self.msrv);
 +                        if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
 +                            iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
 +                        }
 +                    } else {
 +                        map_err_ignore::check(cx, expr, m_arg);
 +                    }
 +                    if let Some((name, recv2, args, span2,_)) = method_call(recv) {
 +                        match (name, args) {
 +                            ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
 +                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
 +                            ("filter", [f_arg]) => {
 +                                filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
 +                            },
 +                            ("find", [f_arg]) => {
 +                                filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
 +                            },
 +                            _ => {},
 +                        }
 +                    }
 +                    map_identity::check(cx, expr, recv, m_arg, name, span);
 +                },
 +                ("map_or", [def, map]) => {
 +                    option_map_or_none::check(cx, expr, recv, def, map);
 +                    manual_ok_or::check(cx, expr, recv, def, map);
 +                },
 +                ("next", []) => {
 +                    if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
 +                        match (name2, args2) {
 +                            ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
 +                            ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
 +                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
 +                            ("iter", []) => iter_next_slice::check(cx, expr, recv2),
 +                            ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
 +                            ("skip_while", [_]) => skip_while_next::check(cx, expr),
 +                            _ => {},
 +                        }
 +                    }
 +                },
 +                ("nth", [n_arg]) => match method_call(recv) {
 +                    Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
 +                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
 +                    Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
 +                    Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
 +                    _ => iter_nth_zero::check(cx, expr, recv, n_arg),
 +                },
 +                ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
 +                ("open", [_]) => {
 +                    open_options::check(cx, expr, recv);
 +                },
 +                ("or_else", [arg]) => {
 +                    if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
 +                        unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
 +                    }
 +                },
 +                ("push", [arg]) => {
 +                    path_buf_push_overwrite::check(cx, expr, arg);
 +                },
 +                ("read_to_end", [_]) => {
 +                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
 +                },
 +                ("read_to_string", [_]) => {
 +                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
 +                },
 +                ("repeat", [arg]) => {
 +                    repeat_once::check(cx, expr, recv, arg);
 +                },
 +                (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
 +                    no_effect_replace::check(cx, expr, arg1, arg2);
 +
 +                    // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
++                    if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY)
++                        && name == "replace"
++                        && let Some(("replace", ..)) = method_call(recv)
++                    {
 +                        collapsible_str_replace::check(cx, expr, arg1, arg2);
 +                    }
 +                },
 +                ("resize", [count_arg, default_arg]) => {
 +                    vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
 +                },
 +                ("seek", [arg]) => {
 +                    if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
 +                        seek_from_current::check(cx, expr, recv, arg);
 +                    }
 +                    if self.msrv.meets(msrvs::SEEK_REWIND) {
 +                        seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
 +                    }
 +                },
 +                ("sort", []) => {
 +                    stable_sort_primitive::check(cx, expr, recv);
 +                },
 +                ("sort_by", [arg]) => {
 +                    unnecessary_sort_by::check(cx, expr, recv, arg, false);
 +                },
 +                ("sort_unstable_by", [arg]) => {
 +                    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) {
 +                        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) {
 +                        suspicious_splitn::check(cx, name, expr, recv, count);
 +                    }
 +                },
 +                ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
 +                ("take", [_arg]) => {
 +                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
 +                        if let ("cloned", []) = (name2, args2) {
 +                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
 +                        }
 +                    }
 +                },
 +                ("take", []) => needless_option_take::check(cx, expr, recv),
 +                ("then", [arg]) => {
 +                    if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
 +                        return;
 +                    }
 +                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
 +                },
 +                ("to_owned", []) => {
 +                    if !suspicious_to_owned::check(cx, expr, recv) {
 +                        implicit_clone::check(cx, name, expr, recv);
 +                    }
 +                },
 +                ("to_os_string" | "to_path_buf" | "to_vec", []) => {
 +                    implicit_clone::check(cx, name, expr, recv);
 +                },
 +                ("unwrap", []) => {
 +                    match method_call(recv) {
 +                        Some(("get", recv, [get_arg], _, _)) => {
 +                            get_unwrap::check(cx, expr, recv, get_arg, false);
 +                        },
 +                        Some(("get_mut", recv, [get_arg], _, _)) => {
 +                            get_unwrap::check(cx, expr, recv, get_arg, true);
 +                        },
 +                        Some(("or", recv, [or_arg], or_span, _)) => {
 +                            or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
 +                        },
 +                        _ => {},
 +                    }
 +                    unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
 +                },
 +                ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
 +                ("unwrap_or", [u_arg]) => match method_call(recv) {
 +                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
 +                        manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
 +                    },
 +                    Some(("map", m_recv, [m_arg], span, _)) => {
 +                        option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
 +                    },
 +                    Some(("then_some", t_recv, [t_arg], _, _)) => {
 +                        obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
 +                    },
 +                    _ => {},
 +                },
 +                ("unwrap_or_else", [u_arg]) => match method_call(recv) {
 +                    Some(("map", recv, [map_arg], _, _))
 +                        if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
 +                    _ => {
 +                        unwrap_or_else_default::check(cx, expr, recv, u_arg);
 +                        unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
 +                    },
 +                },
 +                ("zip", [arg]) => {
 +                    if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
 +                        && name.ident.name == sym::iter
 +                    {
 +                        range_zip_with_len::check(cx, expr, iter_recv, arg);
 +                    }
 +                },
 +                _ => {},
 +            }
 +        }
 +    }
 +}
 +
 +fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
 +    if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
 +        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
 +    }
 +}
 +
 +/// Used for `lint_binary_expr_with_method_call`.
 +#[derive(Copy, Clone)]
 +struct BinaryExprInfo<'a> {
 +    expr: &'a hir::Expr<'a>,
 +    chain: &'a hir::Expr<'a>,
 +    other: &'a hir::Expr<'a>,
 +    eq: bool,
 +}
 +
 +/// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 +fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
 +    macro_rules! lint_with_both_lhs_and_rhs {
 +        ($func:expr, $cx:expr, $info:ident) => {
 +            if !$func($cx, $info) {
 +                ::std::mem::swap(&mut $info.chain, &mut $info.other);
 +                if $func($cx, $info) {
 +                    return;
 +                }
 +            }
 +        };
 +    }
 +
 +    lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
 +}
 +
 +const FN_HEADER: hir::FnHeader = hir::FnHeader {
 +    unsafety: hir::Unsafety::Normal,
 +    constness: hir::Constness::NotConst,
 +    asyncness: hir::IsAsync::NotAsync,
 +    abi: rustc_target::spec::abi::Abi::Rust,
 +};
 +
 +struct ShouldImplTraitCase {
 +    trait_name: &'static str,
 +    method_name: &'static str,
 +    param_count: usize,
 +    fn_header: hir::FnHeader,
 +    // implicit self kind expected (none, self, &self, ...)
 +    self_kind: SelfKind,
 +    // checks against the output type
 +    output_type: OutType,
 +    // certain methods with explicit lifetimes can't implement the equivalent trait method
 +    lint_explicit_lifetime: bool,
 +}
 +impl ShouldImplTraitCase {
 +    const fn new(
 +        trait_name: &'static str,
 +        method_name: &'static str,
 +        param_count: usize,
 +        fn_header: hir::FnHeader,
 +        self_kind: SelfKind,
 +        output_type: OutType,
 +        lint_explicit_lifetime: bool,
 +    ) -> ShouldImplTraitCase {
 +        ShouldImplTraitCase {
 +            trait_name,
 +            method_name,
 +            param_count,
 +            fn_header,
 +            self_kind,
 +            output_type,
 +            lint_explicit_lifetime,
 +        }
 +    }
 +
 +    fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
 +        self.lint_explicit_lifetime
 +            || !impl_item.generics.params.iter().any(|p| {
 +                matches!(
 +                    p.kind,
 +                    hir::GenericParamKind::Lifetime {
 +                        kind: hir::LifetimeParamKind::Explicit
 +                    }
 +                )
 +            })
 +    }
 +}
 +
 +#[rustfmt::skip]
 +const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
 +    ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
 +    ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
 +    ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
 +    ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
 +    ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +];
 +
 +#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 +enum SelfKind {
 +    Value,
 +    Ref,
 +    RefMut,
 +    No, // When we want the first argument type to be different than `Self`
 +}
 +
 +impl SelfKind {
 +    fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +        fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +            if ty == parent_ty {
 +                true
 +            } else if ty.is_box() {
 +                ty.boxed_ty() == parent_ty
 +            } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
 +                if let ty::Adt(_, substs) = ty.kind() {
 +                    substs.types().next().map_or(false, |t| t == parent_ty)
 +                } else {
 +                    false
 +                }
 +            } else {
 +                false
 +            }
 +        }
 +
 +        fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +            if let ty::Ref(_, t, m) = *ty.kind() {
 +                return m == mutability && t == parent_ty;
 +            }
 +
 +            let trait_sym = match mutability {
 +                hir::Mutability::Not => sym::AsRef,
 +                hir::Mutability::Mut => sym::AsMut,
 +            };
 +
 +            let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
 +                return false
 +            };
 +            implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
 +        }
 +
 +        fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +            !matches_value(cx, parent_ty, ty)
 +                && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty)
 +                && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty)
 +        }
 +
 +        match self {
 +            Self::Value => matches_value(cx, parent_ty, ty),
 +            Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
 +            Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
 +            Self::No => matches_none(cx, parent_ty, ty),
 +        }
 +    }
 +
 +    #[must_use]
 +    fn description(self) -> &'static str {
 +        match self {
 +            Self::Value => "`self` by value",
 +            Self::Ref => "`self` by reference",
 +            Self::RefMut => "`self` by mutable reference",
 +            Self::No => "no `self`",
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OutType {
 +    Unit,
 +    Bool,
 +    Any,
 +    Ref,
 +}
 +
 +impl OutType {
 +    fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
 +        let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
 +        match (self, ty) {
 +            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
 +            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
 +            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
 +            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
 +            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
 +    expected.constness == actual.constness
 +        && expected.unsafety == actual.unsafety
 +        && expected.asyncness == actual.asyncness
 +}
index 7e3bed1e41a9457d9ca485d17ac4c0b92cf52dc7,0000000000000000000000000000000000000000..660b7049cce974df23d916d36959aae105e45139
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,49 @@@
- use clippy_utils::{get_trait_def_id, match_def_path, paths};
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::ty::implements_trait;
++use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
 +use rustc_ast::ast::{LitIntType, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::LateContext;
 +use rustc_span::Span;
 +
 +use super::SEEK_TO_START_INSTEAD_OF_REWIND;
 +
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    recv: &'tcx Expr<'_>,
 +    arg: &'tcx Expr<'_>,
 +    name_span: Span,
 +) {
 +    // Get receiver type
 +    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 +
++    if is_expr_used_or_unified(cx.tcx, expr) {
++        return;
++    }
++
 +    if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
 +        implements_trait(cx, ty, seek_trait_id, &[]) &&
 +        let ExprKind::Call(func, args1) = arg.kind &&
 +        let ExprKind::Path(ref path) = func.kind &&
 +        let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
 +        match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
 +        args1.len() == 1 &&
 +        let ExprKind::Lit(ref lit) = args1[0].kind &&
 +        let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
 +    {
 +        let method_call_span = expr.span.with_lo(name_span.lo());
 +        span_lint_and_then(
 +            cx,
 +            SEEK_TO_START_INSTEAD_OF_REWIND,
 +            method_call_span,
 +            "used `seek` to go to the start of the stream",
 +            |diag| {
 +                let app = Applicability::MachineApplicable;
 +
 +                diag.span_suggestion(method_call_span, "replace with", "rewind()", app);
 +            },
 +        );
 +    }
 +}
index 516dee20f8b15f17266ca589927a2631361f7072,0000000000000000000000000000000000000000..9f4beb92b9d2e77bc265e5f13eb3b050989fc77a
mode 100644,000000..100644
--- /dev/null
@@@ -1,335 -1,0 +1,353 @@@
- use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then};
 +use clippy_utils::source::{snippet, snippet_opt};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::FnKind;
 +use rustc_hir::{
 +    self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
 +    Stmt, StmtKind, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::lint::in_external_macro;
- use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq};
++use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::hygiene::DesugaringKind;
 +use rustc_span::source_map::{ExpnKind, Span};
 +
 +use clippy_utils::sugg::Sugg;
- declare_lint_pass!(MiscLints => [
++use clippy_utils::{
++    get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
++};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for function arguments and let bindings denoted as
 +    /// `ref`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `ref` declaration makes the function take an owned
 +    /// value, but turns the argument into a reference (which means that the value
 +    /// is destroyed when exiting the function). This adds not much value: either
 +    /// take a reference type, or take an owned value and create references in the
 +    /// body.
 +    ///
 +    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
 +    /// type of `x` is more obvious with the former.
 +    ///
 +    /// ### Known problems
 +    /// If the argument is dereferenced within the function,
 +    /// removing the `ref` will lead to errors. This can be fixed by removing the
 +    /// dereferences, e.g., changing `*x` to `x` within the function.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn foo(ref _x: u8) {}
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// fn foo(_x: &u8) {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TOPLEVEL_REF_ARG,
 +    style,
 +    "an entire binding declared as `ref`, in a function argument or a `let` statement"
 +}
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of bindings with a single leading
 +    /// underscore.
 +    ///
 +    /// ### Why is this bad?
 +    /// A single leading underscore is usually used to indicate
 +    /// that a binding will not be used. Using such a binding breaks this
 +    /// expectation.
 +    ///
 +    /// ### Known problems
 +    /// The lint does not work properly with desugaring and
 +    /// macro, it has been allowed in the mean time.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _x = 0;
 +    /// let y = _x + 1; // Here we are using `_x`, even though it has a leading
 +    ///                 // underscore. We should rename `_x` to `x`
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USED_UNDERSCORE_BINDING,
 +    pedantic,
 +    "using a binding which is prefixed with an underscore"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of short circuit boolean conditions as
 +    /// a
 +    /// statement.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using a short circuit boolean condition as a statement
 +    /// may hide the fact that the second part is executed or not depending on the
 +    /// outcome of the first part.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// f() && g(); // We should write `if f() { g(); }`.
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHORT_CIRCUIT_STATEMENT,
 +    complexity,
 +    "using a short circuit boolean condition as a statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Catch casts from `0` to some pointer type
 +    ///
 +    /// ### Why is this bad?
 +    /// This generally means `null` and is better expressed as
 +    /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = 0 as *const u32;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = std::ptr::null::<u32>();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ZERO_PTR,
 +    style,
 +    "using `0 as *{const, mut} T`"
 +}
 +
- impl<'tcx> LateLintPass<'tcx> for MiscLints {
++pub struct LintPass {
++    std_or_core: &'static str,
++}
++impl Default for LintPass {
++    fn default() -> Self {
++        Self { std_or_core: "std" }
++    }
++}
++impl_lint_pass!(LintPass => [
 +    TOPLEVEL_REF_ARG,
 +    USED_UNDERSCORE_BINDING,
 +    SHORT_CIRCUIT_STATEMENT,
 +    ZERO_PTR,
 +]);
 +
-             check_cast(cx, expr.span, e, ty);
++impl<'tcx> LateLintPass<'tcx> for LintPass {
++    fn check_crate(&mut self, cx: &LateContext<'_>) {
++        if is_no_std_crate(cx) {
++            self.std_or_core = "core";
++        }
++    }
++
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        k: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        span: Span,
 +        _: HirId,
 +    ) {
 +        if let FnKind::Closure = k {
 +            // Does not apply to closures
 +            return;
 +        }
 +        if in_external_macro(cx.tcx.sess, span) {
 +            return;
 +        }
 +        for arg in iter_input_pats(decl, body) {
 +            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
 +                span_lint(
 +                    cx,
 +                    TOPLEVEL_REF_ARG,
 +                    arg.pat.span,
 +                    "`ref` directly on a function argument is ignored. \
 +                    Consider using a reference type instead",
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.tcx.sess, stmt.span);
 +            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;
 +            then {
 +                // use the macro callsite when the init span (but not the whole local span)
 +                // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
 +                let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() {
 +                    Sugg::hir_with_macro_callsite(cx, init, "..")
 +                } else {
 +                    Sugg::hir(cx, init, "..")
 +                };
 +                let (mutopt, initref) = if mutabl == Mutability::Mut {
 +                    ("mut ", sugg_init.mut_addr())
 +                } else {
 +                    ("", sugg_init.addr())
 +                };
 +                let tyopt = if let Some(ty) = local.ty {
 +                    format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, ".."))
 +                } else {
 +                    String::new()
 +                };
 +                span_lint_hir_and_then(
 +                    cx,
 +                    TOPLEVEL_REF_ARG,
 +                    init.hir_id,
 +                    local.pat.span,
 +                    "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
 +                    |diag| {
 +                        diag.span_suggestion(
 +                            stmt.span,
 +                            "try",
 +                            format!(
 +                                "let {name}{tyopt} = {initref};",
 +                                name=snippet(cx, name.span, ".."),
 +                            ),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    }
 +                );
 +            }
 +        };
 +        if_chain! {
 +            if let StmtKind::Semi(expr) = stmt.kind;
 +            if let ExprKind::Binary(ref binop, a, b) = expr.kind;
 +            if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
 +            if let Some(sugg) = Sugg::hir_opt(cx, a);
 +            then {
 +                span_lint_hir_and_then(
 +                    cx,
 +                    SHORT_CIRCUIT_STATEMENT,
 +                    expr.hir_id,
 +                    stmt.span,
 +                    "boolean short circuit operator in statement may be clearer using an explicit test",
 +                    |diag| {
 +                        let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
 +                        diag.span_suggestion(
 +                            stmt.span,
 +                            "replace it with",
 +                            format!(
 +                                "if {sugg} {{ {}; }}",
 +                                &snippet(cx, b.span, ".."),
 +                            ),
 +                            Applicability::MachineApplicable, // snippet
 +                        );
 +                    });
 +            }
 +        };
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Cast(e, ty) = expr.kind {
- fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
-     if_chain! {
-         if let TyKind::Ptr(ref mut_ty) = ty.kind;
-         if is_integer_literal(e, 0);
-         if !in_constant(cx, e.hir_id);
-         then {
-             let (msg, sugg_fn) = match mut_ty.mutbl {
-                 Mutability::Mut => ("`0 as *mut _` detected", "std::ptr::null_mut"),
-                 Mutability::Not => ("`0 as *const _` detected", "std::ptr::null"),
-             };
++            self.check_cast(cx, expr.span, e, ty);
 +            return;
 +        }
 +        if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) {
 +            // Don't lint things expanded by #[derive(...)], etc or `await` desugaring
 +            return;
 +        }
 +        let sym;
 +        let binding = match expr.kind {
 +            ExprKind::Path(ref qpath) if !matches!(qpath, hir::QPath::LangItem(..)) => {
 +                let binding = last_path_segment(qpath).ident.as_str();
 +                if binding.starts_with('_') &&
 +                    !binding.starts_with("__") &&
 +                    binding != "_result" && // FIXME: #944
 +                    is_used(cx, expr) &&
 +                    // don't lint if the declaration is in a macro
 +                    non_macro_local(cx, cx.qpath_res(qpath, expr.hir_id))
 +                {
 +                    Some(binding)
 +                } else {
 +                    None
 +                }
 +            },
 +            ExprKind::Field(_, ident) => {
 +                sym = ident.name;
 +                let name = sym.as_str();
 +                if name.starts_with('_') && !name.starts_with("__") {
 +                    Some(name)
 +                } else {
 +                    None
 +                }
 +            },
 +            _ => None,
 +        };
 +        if let Some(binding) = binding {
 +            span_lint(
 +                cx,
 +                USED_UNDERSCORE_BINDING,
 +                expr.span,
 +                &format!(
 +                    "used binding `{binding}` which is prefixed with an underscore. A leading \
 +                     underscore signals that a binding will not be used"
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +/// Heuristic to see if an expression is used. Should be compatible with
 +/// `unused_variables`'s idea
 +/// of what it means for an expression to be "used".
 +fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind {
 +        ExprKind::Assign(_, rhs, _) | ExprKind::AssignOp(_, _, rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr),
 +        _ => is_used(cx, parent),
 +    })
 +}
 +
 +/// Tests whether an expression is in a macro expansion (e.g., something
 +/// generated by `#[derive(...)]` or the like).
 +fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
 +    use rustc_span::hygiene::MacroKind;
 +    if expr.span.from_expansion() {
 +        let data = expr.span.ctxt().outer_expn_data();
 +        matches!(data.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, _))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Tests whether `res` is a variable defined outside a macro.
 +fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
 +    if let def::Res::Local(id) = res {
 +        !cx.tcx.hir().span(id).from_expansion()
 +    } else {
 +        false
 +    }
 +}
 +
-             let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
-                 (format!("{sugg_fn}()"), Applicability::MachineApplicable)
-             } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
-                 (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable)
-             } else {
-                 // `MaybeIncorrect` as type inference may not work with the suggested code
-                 (format!("{sugg_fn}()"), Applicability::MaybeIncorrect)
-             };
-             span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
++impl LintPass {
++    fn check_cast(&self, cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
++        if_chain! {
++            if let TyKind::Ptr(ref mut_ty) = ty.kind;
++            if is_integer_literal(e, 0);
++            if !in_constant(cx, e.hir_id);
++            then {
++                let (msg, sugg_fn) = match mut_ty.mutbl {
++                    Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
++                    Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
++                };
 +
++                let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
++                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MachineApplicable)
++                } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
++                    (format!("{}::{sugg_fn}::<{mut_ty_snip}>()", self.std_or_core), Applicability::MachineApplicable)
++                } else {
++                    // `MaybeIncorrect` as type inference may not work with the suggested code
++                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MaybeIncorrect)
++                };
++                span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
++            }
 +        }
 +    }
 +}
index 20b82d81a2aeb64e57d11994ceb3755a96e4cde4,0000000000000000000000000000000000000000..4fbc8398e373443d5cc80c80eb2214933bfe786d
mode 100644,000000..100644
--- /dev/null
@@@ -1,198 -1,0 +1,234 @@@
- use rustc_data_structures::fx::FxHashSet;
 +use super::ARITHMETIC_SIDE_EFFECTS;
 +use clippy_utils::{
 +    consts::{constant, constant_simple},
 +    diagnostics::span_lint,
 +    peel_hir_expr_refs,
 +};
 +use rustc_ast as ast;
- const HARD_CODED_ALLOWED: &[&str] = &[
-     "&str",
-     "f32",
-     "f64",
-     "std::num::Saturating",
-     "std::num::Wrapping",
-     "std::string::String",
++use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +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};
 +
-     allowed: FxHashSet<String>,
++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"],
 +];
++const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
 +
 +#[derive(Debug)]
 +pub struct ArithmeticSideEffects {
-     pub fn new(mut allowed: FxHashSet<String>) -> Self {
-         allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
++    allowed_binary: FxHashMap<String, FxHashSet<String>>,
++    allowed_unary: FxHashSet<String>,
 +    // Used to check whether expressions are constants, such as in enum discriminants and consts
 +    const_span: Option<Span>,
 +    expr_span: Option<Span>,
 +}
 +
 +impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
 +
 +impl ArithmeticSideEffects {
 +    #[must_use]
-             allowed,
++    pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec<String>) -> Self {
++        let mut allowed_binary: FxHashMap<String, FxHashSet<String>> = <_>::default();
++        for [lhs, rhs] in user_allowed_binary.into_iter().chain(
++            HARD_CODED_ALLOWED_BINARY
++                .iter()
++                .copied()
++                .map(|[lhs, rhs]| [lhs.to_string(), rhs.to_string()]),
++        ) {
++            allowed_binary.entry(lhs).or_default().insert(rhs);
++        }
++        let allowed_unary = user_allowed_unary
++            .into_iter()
++            .chain(HARD_CODED_ALLOWED_UNARY.iter().copied().map(String::from))
++            .collect();
 +        Self {
-     /// Checks if the given `expr` has any of the inner `allowed` elements.
-     fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
-         self.allowed
-             .contains(ty.to_string().split('<').next().unwrap_or_default())
++            allowed_binary,
++            allowed_unary,
 +            const_span: None,
 +            expr_span: None,
 +        }
 +    }
 +
-         let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
-         if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
++    /// Checks if the lhs and the rhs types of a binary operation like "addition" or
++    /// "multiplication" are present in the inner set of allowed types.
++    fn has_allowed_binary(&self, lhs_ty: Ty<'_>, rhs_ty: Ty<'_>) -> bool {
++        let lhs_ty_string = lhs_ty.to_string();
++        let lhs_ty_string_elem = lhs_ty_string.split('<').next().unwrap_or_default();
++        let rhs_ty_string = rhs_ty.to_string();
++        let rhs_ty_string_elem = rhs_ty_string.split('<').next().unwrap_or_default();
++        if let Some(rhs_from_specific) = self.allowed_binary.get(lhs_ty_string_elem)
++            && {
++                let rhs_has_allowed_ty = rhs_from_specific.contains(rhs_ty_string_elem);
++                rhs_has_allowed_ty || rhs_from_specific.contains("*")
++            }
++        {
++           true
++        } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") {
++            rhs_from_glob.contains(rhs_ty_string_elem)
++        } else {
++            false
++        }
++    }
++
++    /// Checks if the type of an unary operation like "negation" is present in the inner set of
++    /// allowed types.
++    fn has_allowed_unary(&self, ty: Ty<'_>) -> bool {
++        let ty_string = ty.to_string();
++        let ty_string_elem = ty_string.split('<').next().unwrap_or_default();
++        self.allowed_unary.contains(ty_string_elem)
 +    }
 +
 +    // For example, 8i32 or &i64::MAX.
 +    fn is_integral(ty: Ty<'_>) -> bool {
 +        ty.peel_refs().is_integral()
 +    }
 +
 +    // Common entry-point to avoid code duplication.
 +    fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
 +        let msg = "arithmetic operation that can potentially result in unexpected side-effects";
 +        span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
 +        self.expr_span = Some(expr.span);
 +    }
 +
 +    /// If `expr` is not a literal integer like `1`, returns `None`.
 +    fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
 +        if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
 +            Some(n)
 +        }
 +        else {
 +            None
 +        }
 +    }
 +
 +    /// Manages when the lint should be triggered. Operations in constant environments, hard coded
 +    /// types, custom allowed types and non-constant operations that won't overflow are ignored.
 +    fn manage_bin_ops<'tcx>(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        expr: &hir::Expr<'tcx>,
 +        op: &Spanned<hir::BinOpKind>,
 +        lhs: &hir::Expr<'tcx>,
 +        rhs: &hir::Expr<'tcx>,
 +    ) {
 +        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
 +            return;
 +        }
 +        if !matches!(
 +            op.node,
 +            hir::BinOpKind::Add
 +                | hir::BinOpKind::Sub
 +                | hir::BinOpKind::Mul
 +                | hir::BinOpKind::Div
 +                | hir::BinOpKind::Rem
 +                | hir::BinOpKind::Shl
 +                | hir::BinOpKind::Shr
 +        ) {
 +            return;
 +        };
 +        let lhs_ty = cx.typeck_results().expr_ty(lhs);
 +        let rhs_ty = cx.typeck_results().expr_ty(rhs);
-         if self.is_allowed_ty(ty) {
++        if self.has_allowed_binary(lhs_ty, rhs_ty) {
 +            return;
 +        }
 +        let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
 +            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(actual_lhs), Self::literal_integer(actual_rhs)) {
 +                (None, None) => false,
 +                (None, Some(n)) | (Some(n), None) => match (&op.node, n) {
 +                    (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
 +                    (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
 +                    | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
 +                    | (hir::BinOpKind::Mul, 0 | 1) => true,
 +                    _ => false,
 +                },
 +                (Some(_), Some(_)) => {
 +                    matches!((lhs_ref_counter, rhs_ref_counter), (0, 0))
 +                },
 +            }
 +        } else {
 +            false
 +        };
 +        if !has_valid_op {
 +            self.issue_lint(cx, expr);
 +        }
 +    }
 +
 +    fn manage_unary_ops<'tcx>(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        expr: &hir::Expr<'tcx>,
 +        un_expr: &hir::Expr<'tcx>,
 +        un_op: hir::UnOp,
 +    ) {
 +        let hir::UnOp::Neg = un_op else { return; };
 +        if constant(cx, cx.typeck_results(), un_expr).is_some() {
 +            return;
 +        }
 +        let ty = cx.typeck_results().expr_ty(expr).peel_refs();
++        if self.has_allowed_unary(ty) {
 +            return;
 +        }
 +        let actual_un_expr = peel_hir_expr_refs(un_expr).0;
 +        if Self::literal_integer(actual_un_expr).is_some() {
 +            return;
 +        }
 +        self.issue_lint(cx, expr);
 +    }
 +
 +    fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
 +        self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
 +        if self.should_skip_expr(expr) {
 +            return;
 +        }
 +        match &expr.kind {
 +            hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
 +                self.manage_bin_ops(cx, expr, op, lhs, rhs);
 +            },
 +            hir::ExprKind::Unary(un_op, un_expr) => {
 +                self.manage_unary_ops(cx, expr, un_expr, *un_op);
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
 +        let body_owner = cx.tcx.hir().body_owner(body.id());
 +        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
 +        let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
 +        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
 +            let body_span = cx.tcx.hir().span_with_body(body_owner);
 +            if let Some(span) = self.const_span && span.contains(body_span) {
 +                return;
 +            }
 +            self.const_span = Some(body_span);
 +        }
 +    }
 +
 +    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
 +        let body_owner = cx.tcx.hir().body_owner(body.id());
 +        let body_span = cx.tcx.hir().span(body_owner);
 +        if let Some(span) = self.const_span && span.contains(body_span) {
 +            return;
 +        }
 +        self.const_span = None;
 +    }
 +
 +    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if Some(expr.span) == self.expr_span {
 +            self.expr_span = None;
 +        }
 +    }
 +}
index b48d6c4e2e2af96318e38bdcb81ce5b2f3a548e9,0000000000000000000000000000000000000000..14a12da862efeb68d4f151077dac7859d2ecb9db
mode 100644,000000..100644
--- /dev/null
@@@ -1,148 -1,0 +1,204 @@@
- use clippy_utils::{clip, unsext};
 +use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_applicability;
-                 check_op(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                 check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
++use clippy_utils::{clip, peel_hir_expr_refs, unsext};
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty;
 +use rustc_span::source_map::Span;
 +
 +use super::IDENTITY_OP;
 +
 +pub(crate) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    op: BinOpKind,
 +    left: &'tcx Expr<'_>,
 +    right: &'tcx Expr<'_>,
 +) {
 +    if !is_allowed(cx, op, left, right) {
 +        match op {
 +            BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                 check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
++                check_op(
++                    cx,
++                    left,
++                    0,
++                    expr.span,
++                    peel_hir_expr_refs(right).0.span,
++                    needs_parenthesis(cx, expr, right),
++                );
++                check_op(
++                    cx,
++                    right,
++                    0,
++                    expr.span,
++                    peel_hir_expr_refs(left).0.span,
++                    Parens::Unneeded,
++                );
 +            },
 +            BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-                 check_op(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                 check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded);
++                check_op(
++                    cx,
++                    right,
++                    0,
++                    expr.span,
++                    peel_hir_expr_refs(left).0.span,
++                    Parens::Unneeded,
++                );
 +            },
 +            BinOpKind::Mul => {
-             BinOpKind::Div => check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded),
++                check_op(
++                    cx,
++                    left,
++                    1,
++                    expr.span,
++                    peel_hir_expr_refs(right).0.span,
++                    needs_parenthesis(cx, expr, right),
++                );
++                check_op(
++                    cx,
++                    right,
++                    1,
++                    expr.span,
++                    peel_hir_expr_refs(left).0.span,
++                    Parens::Unneeded,
++                );
 +            },
-                 check_op(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                 check_op(cx, right, -1, expr.span, left.span, Parens::Unneeded);
++            BinOpKind::Div => check_op(
++                cx,
++                right,
++                1,
++                expr.span,
++                peel_hir_expr_refs(left).0.span,
++                Parens::Unneeded,
++            ),
 +            BinOpKind::BitAnd => {
++                check_op(
++                    cx,
++                    left,
++                    -1,
++                    expr.span,
++                    peel_hir_expr_refs(right).0.span,
++                    needs_parenthesis(cx, expr, right),
++                );
++                check_op(
++                    cx,
++                    right,
++                    -1,
++                    expr.span,
++                    peel_hir_expr_refs(left).0.span,
++                    Parens::Unneeded,
++                );
 +            },
 +            BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
 +            _ => (),
 +        }
 +    }
 +}
 +
 +#[derive(Copy, Clone)]
 +enum Parens {
 +    Needed,
 +    Unneeded,
 +}
 +
 +/// Checks if `left op right` needs parenthesis when reduced to `right`
 +/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced
 +/// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be
 +/// interpreted as a statement
 +///
 +/// See #8724
 +fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> Parens {
 +    match right.kind {
 +        ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => {
 +            // ensure we're checking against the leftmost expression of `right`
 +            //
 +            //     ~~~ `lhs`
 +            // 0 + {4} * 2
 +            //     ~~~~~~~ `right`
 +            return needs_parenthesis(cx, binary, lhs);
 +        },
 +        ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {},
 +        _ => return Parens::Unneeded,
 +    }
 +
 +    let mut prev_id = binary.hir_id;
 +    for (_, node) in cx.tcx.hir().parent_iter(binary.hir_id) {
 +        if let Node::Expr(expr) = node
 +            && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) = expr.kind
 +            && lhs.hir_id == prev_id
 +        {
 +            // keep going until we find a node that encompasses left of `binary`
 +            prev_id = expr.hir_id;
 +            continue;
 +        }
 +
 +        match node {
 +            Node::Block(_) | Node::Stmt(_) => break,
 +            _ => return Parens::Unneeded,
 +        };
 +    }
 +
 +    Parens::Needed
 +}
 +
 +fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool {
 +    // This lint applies to integers
 +    !cx.typeck_results().expr_ty(left).peel_refs().is_integral()
 +        || !cx.typeck_results().expr_ty(right).peel_refs().is_integral()
 +        // `1 << 0` is a common pattern in bit manipulation code
 +        || (cmp == BinOpKind::Shl
 +            && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
 +            && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
 +}
 +
 +fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
 +    let lhs_const = constant_full_int(cx, cx.typeck_results(), left);
 +    let rhs_const = constant_full_int(cx, cx.typeck_results(), right);
 +    if match (lhs_const, rhs_const) {
 +        (Some(FullInt::S(lv)), Some(FullInt::S(rv))) => lv.abs() < rv.abs(),
 +        (Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
 +        _ => return,
 +    } {
 +        span_ineffective_operation(cx, span, arg, Parens::Unneeded);
 +    }
 +}
 +
 +fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens) {
 +    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
 +        let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
 +            ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
 +            ty::Uint(uty) => clip(cx.tcx, !0, uty),
 +            _ => return,
 +        };
 +        if match m {
 +            0 => v == 0,
 +            -1 => v == check,
 +            1 => v == 1,
 +            _ => unreachable!(),
 +        } {
 +            span_ineffective_operation(cx, span, arg, parens);
 +        }
 +    }
 +}
 +
 +fn span_ineffective_operation(cx: &LateContext<'_>, span: Span, arg: Span, parens: Parens) {
 +    let mut applicability = Applicability::MachineApplicable;
 +    let expr_snippet = snippet_with_applicability(cx, arg, "..", &mut applicability);
 +
 +    let suggestion = match parens {
 +        Parens::Needed => format!("({expr_snippet})"),
 +        Parens::Unneeded => expr_snippet.into_owned(),
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        IDENTITY_OP,
 +        span,
 +        "this operation has no effect",
 +        "consider reducing it to",
 +        suggestion,
 +        applicability,
 +    );
 +}
index b8a20d5ebe9bd689e7d996fea0dff6e86d9dcdd4,0000000000000000000000000000000000000000..eba230da6c39b772bb90e600f07d9f2df3fcc9b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,892 -1,0 +1,889 @@@
-     ///
-     /// ### Allowed types
-     /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
 +mod absurd_extreme_comparisons;
 +mod assign_op_pattern;
 +mod bit_mask;
 +mod cmp_nan;
 +mod cmp_owned;
 +mod double_comparison;
 +mod duration_subsec;
 +mod eq_op;
 +mod erasing_op;
 +mod float_cmp;
 +mod float_equality_without_abs;
 +mod identity_op;
 +mod integer_division;
 +mod misrefactored_assign_op;
 +mod modulo_arithmetic;
 +mod modulo_one;
 +mod needless_bitwise_bool;
 +mod numeric_arithmetic;
 +mod op_ref;
 +mod ptr_eq;
 +mod self_assignment;
 +mod verbose_bit_mask;
 +
 +pub(crate) mod arithmetic_side_effects;
 +
 +use rustc_hir::{Body, Expr, ExprKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for comparisons where one side of the relation is
 +    /// either the minimum or maximum value for its type and warns if it involves a
 +    /// case that is always true or always false. Only integer and boolean types are
 +    /// checked.
 +    ///
 +    /// ### Why is this bad?
 +    /// An expression like `min <= x` may misleadingly imply
 +    /// that it is possible for `x` to be less than the minimum. Expressions like
 +    /// `max < x` are probably mistakes.
 +    ///
 +    /// ### Known problems
 +    /// For `usize` the size of the current compile target will
 +    /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
 +    /// a comparison to detect target pointer width will trigger this lint. One can
 +    /// use `mem::sizeof` and compare its value or conditional compilation
 +    /// attributes
 +    /// like `#[cfg(target_pointer_width = "64")] ..` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec: Vec<isize> = Vec::new();
 +    /// if vec.len() <= 0 {}
 +    /// if 100 > i32::MAX {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ABSURD_EXTREME_COMPARISONS,
 +    correctness,
 +    "a comparison with a maximum or minimum value that is always true or false"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks any kind of arithmetic operation of any type.
 +    ///
 +    /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
 +    /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
 +    /// or can panic (`/`, `%`).
 +    ///
 +    /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
 +    /// environments, allowed types and non-constant operations that won't overflow are ignored.
 +    ///
 +    /// ### Why is this bad?
 +    /// For integers, overflow will trigger a panic in debug builds or wrap the result in
 +    /// release mode; division by zero will cause a panic in either mode. As a result, it is
 +    /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
 +    ///
 +    /// #### Example
 +    /// ```rust
 +    /// // `n` can be any number, including `i32::MAX`.
 +    /// fn foo(n: i32) -> i32 {
 +    ///   n + 1
 +    /// }
 +    /// ```
 +    ///
 +    /// Third-party types can also overflow or present unwanted side-effects.
 +    ///
 +    /// #### Example
 +    /// ```ignore,rust
 +    /// use rust_decimal::Decimal;
 +    /// let _n = Decimal::MAX + Decimal::MAX;
 +    /// ```
 +    #[clippy::version = "1.64.0"]
 +    pub ARITHMETIC_SIDE_EFFECTS,
 +    restriction,
 +    "any arithmetic expression that can cause side effects like overflows or panics"
 +}
 +
 +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?
 +    /// For some embedded systems or kernel development, it
 +    /// can be useful to rule out floating-point numbers.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = 0.0;
 +    /// a + 1.0;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FLOAT_ARITHMETIC,
 +    restriction,
 +    "any floating-point arithmetic statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `a = a op b` or `a = b commutative_op a`
 +    /// patterns.
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be written as the shorter `a op= b`.
 +    ///
 +    /// ### Known problems
 +    /// While forbidden by the spec, `OpAssign` traits may have
 +    /// implementations that differ from the regular `Op` impl.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut a = 5;
 +    /// let b = 0;
 +    /// // ...
 +    ///
 +    /// a = a + b;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut a = 5;
 +    /// let b = 0;
 +    /// // ...
 +    ///
 +    /// a += b;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ASSIGN_OP_PATTERN,
 +    style,
 +    "assigning the result of an operation on a variable to that same variable"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `a op= a op b` or `a op= b op a` patterns.
 +    ///
 +    /// ### Why is this bad?
 +    /// Most likely these are bugs where one meant to write `a
 +    /// op= b`.
 +    ///
 +    /// ### Known problems
 +    /// Clippy cannot know for sure if `a op= a op b` should have
 +    /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
 +    /// If `a op= a op b` is really the correct behavior it should be
 +    /// written as `a = a op a op b` as it's less confusing.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut a = 5;
 +    /// let b = 2;
 +    /// // ...
 +    /// a += a + b;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MISREFACTORED_ASSIGN_OP,
 +    suspicious,
 +    "having a variable on both sides of an assign op"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for incompatible bit masks in comparisons.
 +    ///
 +    /// The formula for detecting if an expression of the type `_ <bit_op> m
 +    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
 +    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
 +    /// table:
 +    ///
 +    /// |Comparison  |Bit Op|Example      |is always|Formula               |
 +    /// |------------|------|-------------|---------|----------------------|
 +    /// |`==` or `!=`| `&`  |`x & 2 == 3` |`false`  |`c & m != c`          |
 +    /// |`<`  or `>=`| `&`  |`x & 2 < 3`  |`true`   |`m < c`               |
 +    /// |`>`  or `<=`| `&`  |`x & 1 > 1`  |`false`  |`m <= c`              |
 +    /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false`  |`c \| m != c`         |
 +    /// |`<`  or `>=`| `\|` |`x \| 1 < 1` |`false`  |`m >= c`              |
 +    /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true`   |`m > c`               |
 +    ///
 +    /// ### Why is this bad?
 +    /// If the bits that the comparison cares about are always
 +    /// set to zero or one by the bit mask, the comparison is constant `true` or
 +    /// `false` (depending on mask, compared value, and operators).
 +    ///
 +    /// So the code is actively misleading, and the only reason someone would write
 +    /// this intentionally is to win an underhanded Rust contest or create a
 +    /// test-case for this lint.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// if (x & 1 == 2) { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub BAD_BIT_MASK,
 +    correctness,
 +    "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bit masks in comparisons which can be removed
 +    /// without changing the outcome. The basic structure can be seen in the
 +    /// following table:
 +    ///
 +    /// |Comparison| Bit Op   |Example     |equals |
 +    /// |----------|----------|------------|-------|
 +    /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
 +    /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
 +    ///
 +    /// ### Why is this bad?
 +    /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
 +    /// but still a bit misleading, because the bit mask is ineffective.
 +    ///
 +    /// ### Known problems
 +    /// False negatives: This lint will only match instances
 +    /// where we have figured out the math (which is for a power-of-two compared
 +    /// value). This means things like `x | 1 >= 7` (which would be better written
 +    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
 +    /// uncommon).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// if (x | 1 > 3) {  }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub INEFFECTIVE_BIT_MASK,
 +    correctness,
 +    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bit masks that can be replaced by a call
 +    /// to `trailing_zeros`
 +    ///
 +    /// ### Why is this bad?
 +    /// `x.trailing_zeros() > 4` is much clearer than `x & 15
 +    /// == 0`
 +    ///
 +    /// ### Known problems
 +    /// llvm generates better code for `x & 15 == 0` on x86
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// if x & 0b1111 == 0 { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub VERBOSE_BIT_MASK,
 +    pedantic,
 +    "expressions where a bit mask is less readable than the corresponding method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for double comparisons that could be simplified to a single expression.
 +    ///
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 2;
 +    /// if x == y || x < y {}
 +    /// ```
 +    ///
 +    /// Use instead:
 +    ///
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 2;
 +    /// if x <= y {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DOUBLE_COMPARISONS,
 +    complexity,
 +    "unnecessary double comparisons that can be simplified"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calculation of subsecond microseconds or milliseconds
 +    /// from other `Duration` methods.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more concise to call `Duration::subsec_micros()` or
 +    /// `Duration::subsec_millis()` than to calculate them.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::time::Duration;
 +    /// # let duration = Duration::new(5, 0);
 +    /// let micros = duration.subsec_nanos() / 1_000;
 +    /// let millis = duration.subsec_nanos() / 1_000_000;
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::time::Duration;
 +    /// # let duration = Duration::new(5, 0);
 +    /// let micros = duration.subsec_micros();
 +    /// let millis = duration.subsec_millis();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DURATION_SUBSEC,
 +    complexity,
 +    "checks for calculation of subsecond microseconds or milliseconds"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for equal operands to comparison, logical and
 +    /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
 +    /// `||`, `&`, `|`, `^`, `-` and `/`).
 +    ///
 +    /// ### Why is this bad?
 +    /// This is usually just a typo or a copy and paste error.
 +    ///
 +    /// ### Known problems
 +    /// False negatives: We had some false positives regarding
 +    /// calls (notably [racer](https://github.com/phildawes/racer) had one instance
 +    /// of `x.pop() && x.pop()`), so we removed matching any function or method
 +    /// calls. We may introduce a list of known pure functions in the future.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// if x + 1 == x + 1 {}
 +    ///
 +    /// // or
 +    ///
 +    /// # let a = 3;
 +    /// # let b = 4;
 +    /// assert_eq!(a, a);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EQ_OP,
 +    correctness,
 +    "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for arguments to `==` which have their address
 +    /// taken to satisfy a bound
 +    /// and suggests to dereference the other argument instead
 +    ///
 +    /// ### Why is this bad?
 +    /// It is more idiomatic to dereference the other argument.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// &x == y
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// x == *y
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OP_REF,
 +    style,
 +    "taking a reference to satisfy the type constraints on `==`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for erasing operations, e.g., `x * 0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The whole expression can be replaced by zero.
 +    /// This is most likely not the intended outcome and should probably be
 +    /// corrected
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 1;
 +    /// 0 / x;
 +    /// 0 * x;
 +    /// x & 0;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ERASING_OP,
 +    correctness,
 +    "using erasing operations, e.g., `x * 0` or `y & 0`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for statements of the form `(a - b) < f32::EPSILON` or
 +    /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The code without `.abs()` is more likely to have a bug.
 +    ///
 +    /// ### Known problems
 +    /// If the user can ensure that b is larger than a, the `.abs()` is
 +    /// technically unnecessary. However, it will make the code more robust and doesn't have any
 +    /// large performance implications. If the abs call was deliberately left out for performance
 +    /// reasons, it is probably better to state this explicitly in the code, which then can be done
 +    /// with an allow.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
 +    ///     (a - b) < f32::EPSILON
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
 +    ///     (a - b).abs() < f32::EPSILON
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.48.0"]
 +    pub FLOAT_EQUALITY_WITHOUT_ABS,
 +    suspicious,
 +    "float equality check without `.abs()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for identity operations, e.g., `x + 0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This code can be removed without changing the
 +    /// meaning. So it just obscures what's going on. Delete it mercilessly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// x / 1 + 0 * 1 - 0 | 0;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub IDENTITY_OP,
 +    complexity,
 +    "using identity operations, e.g., `x + 0` or `y / 1`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for division of integers
 +    ///
 +    /// ### Why is this bad?
 +    /// When outside of some very specific algorithms,
 +    /// integer division is very often a mistake because it discards the
 +    /// remainder.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 3 / 2;
 +    /// println!("{}", x);
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = 3f32 / 2f32;
 +    /// println!("{}", x);
 +    /// ```
 +    #[clippy::version = "1.37.0"]
 +    pub INTEGER_DIVISION,
 +    restriction,
 +    "integer division may cause loss of precision"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for comparisons to NaN.
 +    ///
 +    /// ### Why is this bad?
 +    /// NaN does not compare meaningfully to anything – not
 +    /// even itself – so those comparisons are simply wrong.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1.0;
 +    /// if x == f32::NAN { }
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = 1.0f32;
 +    /// if x.is_nan() { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CMP_NAN,
 +    correctness,
 +    "comparisons to `NAN`, which will always return false, probably not intended"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for conversions to owned values just for the sake
 +    /// of a comparison.
 +    ///
 +    /// ### Why is this bad?
 +    /// The comparison can operate on a reference, so creating
 +    /// an owned value effectively throws it away directly afterwards, which is
 +    /// needlessly consuming code and heap space.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = "foo";
 +    /// # let y = String::from("foo");
 +    /// if x.to_owned() == y {}
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = "foo";
 +    /// # let y = String::from("foo");
 +    /// if x == y {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CMP_OWNED,
 +    perf,
 +    "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for (in-)equality comparisons on floating-point
 +    /// values (apart from zero), except in functions called `*eq*` (which probably
 +    /// implement equality for a type involving floats).
 +    ///
 +    /// ### Why is this bad?
 +    /// Floating point calculations are usually imprecise, so
 +    /// asking if two values are *exactly* equal is asking for trouble. For a good
 +    /// guide on what to do, see [the floating point
 +    /// guide](http://www.floating-point-gui.de/errors/comparison).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 1.2331f64;
 +    /// let y = 1.2332f64;
 +    ///
 +    /// if y == 1.23f64 { }
 +    /// if y != x {} // where both are floats
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x = 1.2331f64;
 +    /// # let y = 1.2332f64;
 +    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
 +    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
 +    /// // let error_margin = std::f64::EPSILON;
 +    /// if (y - 1.23f64).abs() < error_margin { }
 +    /// if (y - x).abs() > error_margin { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FLOAT_CMP,
 +    pedantic,
 +    "using `==` or `!=` on float values instead of comparing difference with an epsilon"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for (in-)equality comparisons on floating-point
 +    /// value and constant, except in functions called `*eq*` (which probably
 +    /// implement equality for a type involving floats).
 +    ///
 +    /// ### Why is this bad?
 +    /// Floating point calculations are usually imprecise, so
 +    /// asking if two values are *exactly* equal is asking for trouble. For a good
 +    /// guide on what to do, see [the floating point
 +    /// guide](http://www.floating-point-gui.de/errors/comparison).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: f64 = 1.0;
 +    /// const ONE: f64 = 1.00;
 +    ///
 +    /// if x == ONE { } // where both are floats
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// # let x: f64 = 1.0;
 +    /// # const ONE: f64 = 1.00;
 +    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
 +    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
 +    /// // let error_margin = std::f64::EPSILON;
 +    /// if (x - ONE).abs() < error_margin { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FLOAT_CMP_CONST,
 +    restriction,
 +    "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for getting the remainder of a division by one or minus
 +    /// one.
 +    ///
 +    /// ### Why is this bad?
 +    /// The result for a divisor of one can only ever be zero; for
 +    /// minus one it can cause panic/overflow (if the left operand is the minimal value of
 +    /// the respective integer type) or results in zero. No one will write such code
 +    /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that
 +    /// contest, it's probably a bad idea. Use something more underhanded.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// let a = x % 1;
 +    /// let a = x % -1;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MODULO_ONE,
 +    correctness,
 +    "taking a number modulo +/-1, which can either panic/overflow or always returns 0"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for modulo arithmetic.
 +    ///
 +    /// ### Why is this bad?
 +    /// The results of modulo (%) operation might differ
 +    /// depending on the language, when negative numbers are involved.
 +    /// If you interop with different languages it might be beneficial
 +    /// to double check all places that use modulo arithmetic.
 +    ///
 +    /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = -17 % 3;
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub MODULO_ARITHMETIC,
 +    restriction,
 +    "any modulo arithmetic statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
 +    /// a lazy and.
 +    ///
 +    /// ### Why is this bad?
 +    /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
 +    /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
 +    ///
 +    /// ### Known problems
 +    /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
 +    /// determination is quite conservative.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let (x,y) = (true, false);
 +    /// if x & !y {} // where both x and y are booleans
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let (x,y) = (true, false);
 +    /// if x && !y {}
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub NEEDLESS_BITWISE_BOOL,
 +    pedantic,
 +    "Boolean expressions that use bitwise rather than lazy operators"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Use `std::ptr::eq` when applicable
 +    ///
 +    /// ### Why is this bad?
 +    /// `ptr::eq` can be used to compare `&T` references
 +    /// (which coerce to `*const T` implicitly) by their address rather than
 +    /// comparing the values they point to.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = &[1, 2, 3];
 +    /// let b = &[1, 2, 3];
 +    ///
 +    /// assert!(a as *const _ as usize == b as *const _ as usize);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = &[1, 2, 3];
 +    /// let b = &[1, 2, 3];
 +    ///
 +    /// assert!(std::ptr::eq(a, b));
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub PTR_EQ,
 +    style,
 +    "use `std::ptr::eq` when comparing raw pointers"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for explicit self-assignments.
 +    ///
 +    /// ### Why is this bad?
 +    /// Self-assignments are redundant and unlikely to be
 +    /// intentional.
 +    ///
 +    /// ### Known problems
 +    /// If expression contains any deref coercions or
 +    /// indexing operations they are assumed not to have any side effects.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct Event {
 +    ///     x: i32,
 +    /// }
 +    ///
 +    /// fn copy_position(a: &mut Event, b: &Event) {
 +    ///     a.x = a.x;
 +    /// }
 +    /// ```
 +    ///
 +    /// Should be:
 +    /// ```rust
 +    /// struct Event {
 +    ///     x: i32,
 +    /// }
 +    ///
 +    /// fn copy_position(a: &mut Event, b: &Event) {
 +    ///     a.x = b.x;
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.48.0"]
 +    pub SELF_ASSIGNMENT,
 +    correctness,
 +    "explicit self-assignment"
 +}
 +
 +pub struct Operators {
 +    arithmetic_context: numeric_arithmetic::Context,
 +    verbose_bit_mask_threshold: u64,
 +}
 +impl_lint_pass!(Operators => [
 +    ABSURD_EXTREME_COMPARISONS,
 +    ARITHMETIC_SIDE_EFFECTS,
 +    INTEGER_ARITHMETIC,
 +    FLOAT_ARITHMETIC,
 +    ASSIGN_OP_PATTERN,
 +    MISREFACTORED_ASSIGN_OP,
 +    BAD_BIT_MASK,
 +    INEFFECTIVE_BIT_MASK,
 +    VERBOSE_BIT_MASK,
 +    DOUBLE_COMPARISONS,
 +    DURATION_SUBSEC,
 +    EQ_OP,
 +    OP_REF,
 +    ERASING_OP,
 +    FLOAT_EQUALITY_WITHOUT_ABS,
 +    IDENTITY_OP,
 +    INTEGER_DIVISION,
 +    CMP_NAN,
 +    CMP_OWNED,
 +    FLOAT_CMP,
 +    FLOAT_CMP_CONST,
 +    MODULO_ONE,
 +    MODULO_ARITHMETIC,
 +    NEEDLESS_BITWISE_BOOL,
 +    PTR_EQ,
 +    SELF_ASSIGNMENT,
 +]);
 +impl Operators {
 +    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
 +        Self {
 +            arithmetic_context: numeric_arithmetic::Context::default(),
 +            verbose_bit_mask_threshold,
 +        }
 +    }
 +}
 +impl<'tcx> LateLintPass<'tcx> for Operators {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        eq_op::check_assert(cx, e);
 +        match e.kind {
 +            ExprKind::Binary(op, lhs, rhs) => {
 +                if !e.span.from_expansion() {
 +                    absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs);
 +                    if !(macro_with_not_op(lhs) || macro_with_not_op(rhs)) {
 +                        eq_op::check(cx, e, op.node, lhs, rhs);
 +                        op_ref::check(cx, e, op.node, lhs, rhs);
 +                    }
 +                    erasing_op::check(cx, e, op.node, lhs, rhs);
 +                    identity_op::check(cx, e, op.node, lhs, rhs);
 +                    needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
 +                    ptr_eq::check(cx, e, op.node, lhs, rhs);
 +                }
 +                self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
 +                bit_mask::check(cx, e, op.node, lhs, rhs);
 +                verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
 +                double_comparison::check(cx, op.node, lhs, rhs, e.span);
 +                duration_subsec::check(cx, e, op.node, lhs, rhs);
 +                float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
 +                integer_division::check(cx, e, op.node, lhs, rhs);
 +                cmp_nan::check(cx, e, op.node, lhs, rhs);
 +                cmp_owned::check(cx, op.node, lhs, rhs);
 +                float_cmp::check(cx, e, op.node, lhs, rhs);
 +                modulo_one::check(cx, e, op.node, rhs);
 +                modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
 +            },
 +            ExprKind::AssignOp(op, lhs, rhs) => {
 +                self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
 +                misrefactored_assign_op::check(cx, e, op.node, lhs, rhs);
 +                modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
 +            },
 +            ExprKind::Assign(lhs, rhs, _) => {
 +                assign_op_pattern::check(cx, e, lhs, rhs);
 +                self_assignment::check(cx, e, lhs, rhs);
 +            },
 +            ExprKind::Unary(op, arg) => {
 +                if op == UnOp::Neg {
 +                    self.arithmetic_context.check_negate(cx, e, arg);
 +                }
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_expr_post(&mut self, _: &LateContext<'_>, e: &Expr<'_>) {
 +        self.arithmetic_context.expr_post(e.hir_id);
 +    }
 +
 +    fn check_body(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
 +        self.arithmetic_context.enter_body(cx, b);
 +    }
 +
 +    fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
 +        self.arithmetic_context.body_post(cx, b);
 +    }
 +}
 +
 +fn macro_with_not_op(e: &Expr<'_>) -> bool {
 +    if let ExprKind::Unary(_, e) = e.kind {
 +        e.span.from_expansion()
 +    } else {
 +        false
 +    }
 +}
index d612d249c2f000ab3c869952f1806ff491ac2450,0000000000000000000000000000000000000000..c2a8db7df038b9355ca6abf1e9833436688ce033
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,99 @@@
-         if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use rustc_errors::Applicability;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::{Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::def_id::CRATE_DEF_ID;
 +use rustc_span::hygiene::MacroKind;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for items declared `pub(crate)` that are not crate visible because they
 +    /// are inside a private module.
 +    ///
 +    /// ### Why is this bad?
 +    /// Writing `pub(crate)` is misleading when it's redundant due to the parent
 +    /// module's visibility.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// mod internal {
 +    ///     pub(crate) fn internal_fn() { }
 +    /// }
 +    /// ```
 +    /// This function is not visible outside the module and it can be declared with `pub` or
 +    /// private visibility
 +    /// ```rust
 +    /// mod internal {
 +    ///     pub fn internal_fn() { }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub REDUNDANT_PUB_CRATE,
 +    nursery,
 +    "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them."
 +}
 +
 +#[derive(Default)]
 +pub struct RedundantPubCrate {
 +    is_exported: Vec<bool>,
 +}
 +
 +impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 +        if_chain! {
 +            if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
 +            if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false);
 +            if is_not_macro_export(item);
 +            then {
 +                let span = item.span.with_hi(item.ident.span.hi());
 +                let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
 +                span_lint_and_then(
 +                    cx,
 +                    REDUNDANT_PUB_CRATE,
 +                    span,
 +                    &format!("pub(crate) {descr} inside private module"),
 +                    |diag| {
 +                        diag.span_suggestion(
 +                            item.vis_span,
 +                            "consider using",
 +                            "pub".to_string(),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +
 +        if let ItemKind::Mod { .. } = item.kind {
 +            self.is_exported
 +                .push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 +        if let ItemKind::Mod { .. } = item.kind {
 +            self.is_exported.pop().expect("unbalanced check_item/check_item_post");
 +        }
 +    }
 +}
 +
 +fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
 +    if let ItemKind::Use(path, _) = item.kind {
++        if path
++            .res
++            .iter()
++            .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
++        {
 +            return false;
 +        }
 +    } else if let ItemKind::Macro(..) = item.kind {
 +        return false;
 +    }
 +
 +    true
 +}
index 3aa2490bc44e018fa32371b1f94e0c69a46e4892,0000000000000000000000000000000000000000..41f991a967bfd9929b025657ef21c8fc0aa573ca
mode 100644,000000..100644
--- /dev/null
@@@ -1,116 -1,0 +1,116 @@@
-                                 let sugg = format!("&{snip}");
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::msrvs::{self, Msrv};
 +use clippy_utils::source::snippet;
 +use rustc_ast::ast::{Item, ItemKind, Ty, TyKind};
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for constants and statics with an explicit `'static` lifetime.
 +    ///
 +    /// ### Why is this bad?
 +    /// Adding `'static` to every reference can create very
 +    /// complicated types.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
 +    /// &[...]
 +    /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
 +    /// &[...]
 +    /// ```
 +    /// This code can be rewritten as
 +    /// ```ignore
 +    ///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
 +    ///  static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
 +    /// ```
 +    #[clippy::version = "1.37.0"]
 +    pub REDUNDANT_STATIC_LIFETIMES,
 +    style,
 +    "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
 +}
 +
 +pub struct RedundantStaticLifetimes {
 +    msrv: Msrv,
 +}
 +
 +impl RedundantStaticLifetimes {
 +    #[must_use]
 +    pub fn new(msrv: Msrv) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
 +
 +impl RedundantStaticLifetimes {
 +    // Recursively visit types
 +    fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
 +        match ty.kind {
 +            // Be careful of nested structures (arrays and tuples)
 +            TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
 +                Self::visit_type(ty, cx, reason);
 +            },
 +            TyKind::Tup(ref tup) => {
 +                for tup_ty in tup {
 +                    Self::visit_type(tup_ty, cx, reason);
 +                }
 +            },
 +            // This is what we are looking for !
 +            TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
 +                // Match the 'static lifetime
 +                if let Some(lifetime) = *optional_lifetime {
 +                    match borrow_type.ty.kind {
 +                        TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
 +                            if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
 +                                let snip = snippet(cx, borrow_type.ty.span, "<type>");
++                                let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
 +                                span_lint_and_then(
 +                                    cx,
 +                                    REDUNDANT_STATIC_LIFETIMES,
 +                                    lifetime.ident.span,
 +                                    reason,
 +                                    |diag| {
 +                                        diag.span_suggestion(
 +                                            ty.span,
 +                                            "consider removing `'static`",
 +                                            sugg,
 +                                            Applicability::MachineApplicable, //snippet
 +                                        );
 +                                    },
 +                                );
 +                            }
 +                        },
 +                        _ => {},
 +                    }
 +                }
 +                Self::visit_type(&borrow_type.ty, cx, reason);
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +impl EarlyLintPass for RedundantStaticLifetimes {
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 +        if !self.msrv.meets(msrvs::STATIC_IN_CONST) {
 +            return;
 +        }
 +
 +        if !item.span.from_expansion() {
 +            if let ItemKind::Const(_, ref var_type, _) = item.kind {
 +                Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
 +                // Don't check associated consts because `'static` cannot be elided on those (issue
 +                // #2438)
 +            }
 +
 +            if let ItemKind::Static(ref var_type, _, _) = item.kind {
 +                Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(EarlyContext);
 +}
index 8e214218f23ae1d5f617147d4e9ca2ff42cb37af,0000000000000000000000000000000000000000..72c25592609ba77191f7877134b6c8bff1df90d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,46 @@@
 +// This file is managed by `cargo dev rename_lint`. Prefer using that when possible.
 +
 +#[rustfmt::skip]
 +pub static RENAMED_LINTS: &[(&str, &str)] = &[
++    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
 +    ("clippy::blacklisted_name", "clippy::disallowed_names"),
 +    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
 +    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
 +    ("clippy::box_vec", "clippy::box_collection"),
 +    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
 +    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
 +    ("clippy::disallowed_method", "clippy::disallowed_methods"),
 +    ("clippy::disallowed_type", "clippy::disallowed_types"),
 +    ("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::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"),
 +    ("clippy::option_expect_used", "clippy::expect_used"),
 +    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
 +    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
 +    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
 +    ("clippy::ref_in_deref", "clippy::needless_borrow"),
 +    ("clippy::result_expect_used", "clippy::expect_used"),
 +    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
 +    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
 +    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
 +    ("clippy::stutter", "clippy::module_name_repetitions"),
 +    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
 +    ("clippy::zero_width_space", "clippy::invisible_characters"),
 +    ("clippy::drop_bounds", "drop_bounds"),
 +    ("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::into_iter_on_array", "array_into_iter"),
 +    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
 +    ("clippy::invalid_ref", "invalid_value"),
 +    ("clippy::let_underscore_drop", "let_underscore_drop"),
 +    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
 +    ("clippy::panic_params", "non_fmt_panics"),
 +    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
 +    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
 +    ("clippy::unknown_clippy_lints", "unknown_lints"),
 +    ("clippy::unused_label", "unused_labels"),
 +];
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8f1d1490e1f085689ffb41be7407acbcd01e2bda
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,137 @@@
++use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
++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_span::Span;
++
++declare_clippy_lint! {
++    /// ### What it does
++    ///
++    /// Suggests moving the semicolon after a block to the inside of the block, after its last
++    /// expression.
++    ///
++    /// ### Why is this bad?
++    ///
++    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
++    /// and this lint suggests inside the block.
++    /// Take a look at `semicolon_outside_block` for the other alternative.
++    ///
++    /// ### Example
++    ///
++    /// ```rust
++    /// # fn f(_: u32) {}
++    /// # let x = 0;
++    /// unsafe { f(x) };
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// # fn f(_: u32) {}
++    /// # let x = 0;
++    /// unsafe { f(x); }
++    /// ```
++    #[clippy::version = "1.66.0"]
++    pub SEMICOLON_INSIDE_BLOCK,
++    restriction,
++    "add a semicolon inside the block"
++}
++declare_clippy_lint! {
++    /// ### What it does
++    ///
++    /// Suggests moving the semicolon from a block's final expression outside of the block.
++    ///
++    /// ### Why is this bad?
++    ///
++    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
++    /// and this lint suggests outside the block.
++    /// Take a look at `semicolon_inside_block` for the other alternative.
++    ///
++    /// ### Example
++    ///
++    /// ```rust
++    /// # fn f(_: u32) {}
++    /// # let x = 0;
++    /// unsafe { f(x); }
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// # fn f(_: u32) {}
++    /// # let x = 0;
++    /// unsafe { f(x) };
++    /// ```
++    #[clippy::version = "1.66.0"]
++    pub SEMICOLON_OUTSIDE_BLOCK,
++    restriction,
++    "add a semicolon outside the block"
++}
++declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
++
++impl LateLintPass<'_> for SemicolonBlock {
++    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
++        match stmt.kind {
++            StmtKind::Expr(Expr {
++                kind: ExprKind::Block(block, _),
++                ..
++            }) if !block.span.from_expansion() => {
++                let Block {
++                    expr: None,
++                    stmts: [.., stmt],
++                    ..
++                } = block else { return };
++                let &Stmt {
++                    kind: StmtKind::Semi(expr),
++                    span,
++                    ..
++                } = stmt else { return };
++                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),
++            _ => (),
++        }
++    }
++}
++
++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());
++
++    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())],
++            );
++        },
++    );
++}
index f4705481d4e69b3131ad73ce0439ba6903092dca,0000000000000000000000000000000000000000..bc18cad6d381b0cb165d46e6bd000b7c8305d637
mode 100644,000000..100644
--- /dev/null
@@@ -1,517 -1,0 +1,527 @@@
- use clippy_utils::{peel_blocks, SpanlessEq};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
 +use clippy_utils::source::{snippet, snippet_with_applicability};
 +use clippy_utils::ty::is_type_lang_item;
++use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
 +use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
- use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefId;
-                     span_lint_and_sugg(
-                         cx,
-                         STRING_LIT_AS_BYTES,
-                         e.span,
-                         "calling `as_bytes()` on a string literal",
-                         "consider using a byte string literal instead",
-                         format!(
-                             "b{}",
-                             snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
-                         ),
-                         applicability,
-                     );
++use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for string appends of the form `x = x + y` (without
 +    /// `let`!).
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not really bad, but some people think that the
 +    /// `.push_str(_)` method is more readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut x = "Hello".to_owned();
 +    /// x = x + ", World";
 +    ///
 +    /// // More readable
 +    /// x += ", World";
 +    /// x.push_str(", World");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_ADD_ASSIGN,
 +    pedantic,
 +    "using `x = x + ..` where x is a `String` instead of `push_str()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for all instances of `x + _` where `x` is of type
 +    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
 +    /// match.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not bad in and of itself. However, this particular
 +    /// `Add` implementation is asymmetric (the other operand need not be `String`,
 +    /// but `x` does), while addition as mathematically defined is symmetric, also
 +    /// the `String::push_str(_)` function is a perfectly good replacement.
 +    /// Therefore, some dislike it and wish not to have it in their code.
 +    ///
 +    /// That said, other people think that string addition, having a long tradition
 +    /// in other languages is actually fine, which is why we decided to make this
 +    /// particular lint `allow` by default.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = "Hello".to_owned();
 +    /// x + ", World";
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut x = "Hello".to_owned();
 +    /// x.push_str(", World");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_ADD,
 +    restriction,
 +    "using `x + ..` where x is a `String` instead of `push_str()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the `as_bytes` method called on string literals
 +    /// that contain only ASCII characters.
 +    ///
 +    /// ### Why is this bad?
 +    /// Byte string literals (e.g., `b"foo"`) can be used
 +    /// instead. They are shorter but less discoverable than `as_bytes()`.
 +    ///
 +    /// ### Known problems
 +    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
 +    /// equivalent because they have different types. The former is `&[u8]`
 +    /// while the latter is `&[u8; 3]`. That means in general they will have a
 +    /// different set of methods and different trait implementations.
 +    ///
 +    /// ```compile_fail
 +    /// fn f(v: Vec<u8>) {}
 +    ///
 +    /// f("...".as_bytes().to_owned()); // works
 +    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
 +    ///
 +    /// fn g(r: impl std::io::Read) {}
 +    ///
 +    /// g("...".as_bytes()); // works
 +    /// g(b"..."); // does not work
 +    /// ```
 +    ///
 +    /// The actual equivalent of `"str".as_bytes()` with the same type is not
 +    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
 +    /// more readable than a function call.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let bstr = "a byte string".as_bytes();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// let bstr = b"a byte string";
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_LIT_AS_BYTES,
 +    nursery,
 +    "calling `as_bytes` on a string literal instead of using a byte string literal"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for slice operations on strings
 +    ///
 +    /// ### Why is this bad?
 +    /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
 +    /// counts and string indices. This may lead to panics, and should warrant some test cases
 +    /// containing wide UTF-8 characters. This lint is most useful in code that should avoid
 +    /// panics at all costs.
 +    ///
 +    /// ### Known problems
 +    /// 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
 +    /// ```rust,should_panic
 +    /// &"Ölkanne"[1..];
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub STRING_SLICE,
 +    restriction,
 +    "slicing a string"
 +}
 +
 +declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StringAdd {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), e.span) {
 +            return;
 +        }
 +        match e.kind {
 +            ExprKind::Binary(
 +                Spanned {
 +                    node: BinOpKind::Add, ..
 +                },
 +                left,
 +                _,
 +            ) => {
 +                if is_string(cx, left) {
 +                    if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
 +                        let parent = get_parent_expr(cx, e);
 +                        if let Some(p) = parent {
 +                            if let ExprKind::Assign(target, _, _) = p.kind {
 +                                // avoid duplicate matches
 +                                if SpanlessEq::new(cx).eq_expr(target, left) {
 +                                    return;
 +                                }
 +                            }
 +                        }
 +                    }
 +                    span_lint(
 +                        cx,
 +                        STRING_ADD,
 +                        e.span,
 +                        "you added something to a string. Consider using `String::push_str()` instead",
 +                    );
 +                }
 +            },
 +            ExprKind::Assign(target, src, _) => {
 +                if is_string(cx, target) && is_add(cx, src, target) {
 +                    span_lint(
 +                        cx,
 +                        STRING_ADD_ASSIGN,
 +                        e.span,
 +                        "you assigned the result of adding something to this string. Consider using \
 +                         `String::push_str()` instead",
 +                    );
 +                }
 +            },
 +            ExprKind::Index(target, _idx) => {
 +                let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
 +                if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) {
 +                    span_lint(
 +                        cx,
 +                        STRING_SLICE,
 +                        e.span,
 +                        "indexing into a string may panic if the index is within a UTF-8 character",
 +                    );
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
 +}
 +
 +fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
 +    match peel_blocks(src).kind {
 +        ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Add, ..
 +            },
 +            left,
 +            _,
 +        ) => SpanlessEq::new(cx).eq_expr(target, left),
 +        _ => false,
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Check if the string is transformed to byte array and casted back to string.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's unnecessary, the string can be used directly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust
 +    /// &"Hello World!"[6..11];
 +    /// ```
 +    #[clippy::version = "1.50.0"]
 +    pub STRING_FROM_UTF8_AS_BYTES,
 +    complexity,
 +    "casting string slices to byte slices and back"
 +}
 +
 +// Max length a b"foo" string can take
 +const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
 +
 +declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
++    #[expect(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        use rustc_ast::LitKind;
 +
 +        if_chain! {
 +            // Find std::str::converts::from_utf8
 +            if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
 +
 +            // Find string::as_bytes
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
 +            if let ExprKind::Index(left, right) = args.kind;
 +            let (method_names, expressions, _) = method_calls(left, 1);
 +            if method_names.len() == 1;
 +            if expressions.len() == 1;
 +            if expressions[0].1.is_empty();
 +            if method_names[0] == sym!(as_bytes);
 +
 +            // Check for slicer
 +            if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind;
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let string_expression = &expressions[0].0;
 +
 +                let snippet_app = snippet_with_applicability(
 +                    cx,
 +                    string_expression.span, "..",
 +                    &mut applicability,
 +                );
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    STRING_FROM_UTF8_AS_BYTES,
 +                    e.span,
 +                    "calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
 +                    "try",
 +                    format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
 +                    applicability
 +                )
 +            }
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
 +            if path.ident.name == sym!(as_bytes);
 +            if let ExprKind::Lit(lit) = &receiver.kind;
 +            if let LitKind::Str(lit_content, _) = &lit.node;
 +            then {
 +                let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
 +                let mut applicability = Applicability::MachineApplicable;
 +                if callsite.starts_with("include_str!") {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        STRING_LIT_AS_BYTES,
 +                        e.span,
 +                        "calling `as_bytes()` on `include_str!(..)`",
 +                        "consider using `include_bytes!(..)` instead",
 +                        snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
 +                            "include_str",
 +                            "include_bytes",
 +                            1,
 +                        ),
 +                        applicability,
 +                    );
 +                } else if lit_content.as_str().is_ascii()
 +                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
 +                    && !receiver.span.from_expansion()
 +                {
++                    if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
++                        && let Node::Expr(parent) = parent
++                        && let ExprKind::Match(scrutinee, ..) = parent.kind
++                        && scrutinee.hir_id == id
++                    {
++                        // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
++                        // `&[u8]`. This change would prevent matching with different sized slices.
++                    } else {
++                        span_lint_and_sugg(
++                            cx,
++                            STRING_LIT_AS_BYTES,
++                            e.span,
++                            "calling `as_bytes()` on a string literal",
++                            "consider using a byte string literal instead",
++                            format!(
++                                "b{}",
++                                snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
++                            ),
++                            applicability,
++                        );
++                    }
 +                }
 +            }
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
 +            if path.ident.name == sym!(into_bytes);
 +            if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
 +            if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
 +            if let ExprKind::Lit(lit) = &recv.kind;
 +            if let LitKind::Str(lit_content, _) = &lit.node;
 +
 +            if lit_content.as_str().is_ascii();
 +            if lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT;
 +            if !recv.span.from_expansion();
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    STRING_LIT_AS_BYTES,
 +                    e.span,
 +                    "calling `into_bytes()` on a string literal",
 +                    "consider using a byte string literal instead",
 +                    format!(
 +                        "b{}.to_vec()",
 +                        snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability)
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for `.to_string()` method calls on values of type `&str`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `to_string` method is also used on other types to convert them to a string.
 +    /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
 +    /// expressed with `.to_owned()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let _ = "str".to_string();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // example code which does not raise clippy warning
 +    /// let _ = "str".to_owned();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STR_TO_STRING,
 +    restriction,
 +    "using `to_string()` on a `&str`, which should be `to_owned()`"
 +}
 +
 +declare_lint_pass!(StrToString => [STR_TO_STRING]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StrToString {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
 +            if path.ident.name == sym::to_string;
 +            let ty = cx.typeck_results().expr_ty(self_arg);
 +            if let ty::Ref(_, ty, ..) = ty.kind();
 +            if *ty.kind() == ty::Str;
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    STR_TO_STRING,
 +                    expr.span,
 +                    "`to_string()` called on a `&str`",
 +                    None,
 +                    "consider using `.to_owned()`",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for `.to_string()` method calls on values of type `String`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `to_string` method is also used on other types to convert them to a string.
 +    /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let msg = String::from("Hello World");
 +    /// let _ = msg.to_string();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // example code which does not raise clippy warning
 +    /// let msg = String::from("Hello World");
 +    /// let _ = msg.clone();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_TO_STRING,
 +    restriction,
 +    "using `to_string()` on a `String`, which should be `clone()`"
 +}
 +
 +declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StringToString {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
 +            if path.ident.name == sym::to_string;
 +            let ty = cx.typeck_results().expr_ty(self_arg);
 +            if is_type_lang_item(cx, ty, LangItem::String);
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    STRING_TO_STRING,
 +                    expr.span,
 +                    "`to_string()` called on a `String`",
 +                    None,
 +                    "consider using `.clone()`",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `split_whitespace` already ignores leading and trailing whitespace.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// " A B C ".trim().split_whitespace();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// " A B C ".split_whitespace();
 +    /// ```
 +    #[clippy::version = "1.62.0"]
 +    pub TRIM_SPLIT_WHITESPACE,
 +    style,
 +    "using `str::trim()` or alike before `str::split_whitespace`"
 +}
 +declare_lint_pass!(TrimSplitWhitespace => [TRIM_SPLIT_WHITESPACE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +        let tyckres = cx.typeck_results();
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
 +            if path.ident.name == sym!(split_whitespace);
 +            if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
 +            if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
 +            if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
 +            if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
 +            if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
 +            if is_one_of_trim_diagnostic_items(cx, trim_def_id);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    TRIM_SPLIT_WHITESPACE,
 +                    trim_span.with_hi(split_ws_span.lo()),
 +                    &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
 +                    &format!("remove `{trim_fn_name}()`"),
 +                    String::new(),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_one_of_trim_diagnostic_items(cx: &LateContext<'_>, trim_def_id: DefId) -> bool {
 +    cx.tcx.is_diagnostic_item(sym::str_trim, trim_def_id)
 +        || cx.tcx.is_diagnostic_item(sym::str_trim_start, trim_def_id)
 +        || cx.tcx.is_diagnostic_item(sym::str_trim_end, trim_def_id)
 +}
index b6dc8cd7ab1197e338e653a2fa3e1d5f20442877,0000000000000000000000000000000000000000..3e7d0028c0fbd97df2a73e40300db80ac39606fe
mode 100644,000000..100644
--- /dev/null
@@@ -1,581 -1,0 +1,628 @@@
-     /// Lint: Arithmetic.
 +//! Read configurations files.
 +
 +#![allow(clippy::module_name_repetitions)]
 +
 +use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 +use serde::Deserialize;
 +use std::error::Error;
 +use std::path::{Path, PathBuf};
 +use std::str::FromStr;
 +use std::{cmp, env, fmt, fs, io, iter};
 +
 +#[rustfmt::skip]
 +const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
 +    "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",
 +];
 +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 +
 +/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +pub struct Rename {
 +    pub path: String,
 +    pub rename: String,
 +}
 +
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedPath {
 +    Simple(String),
 +    WithReason { path: String, reason: Option<String> },
 +}
 +
 +impl DisallowedPath {
 +    pub fn path(&self) -> &str {
 +        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
 +
 +        path
 +    }
 +
 +    pub fn reason(&self) -> Option<String> {
 +        match self {
 +            Self::WithReason {
 +                reason: Some(reason), ..
 +            } => Some(format!("{reason} (from clippy.toml)")),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +/// Conf with parse errors
 +#[derive(Default)]
 +pub struct TryConf {
 +    pub conf: Conf,
 +    pub errors: Vec<Box<dyn Error>>,
 +    pub warnings: Vec<Box<dyn Error>>,
 +}
 +
 +impl TryConf {
 +    fn from_error(error: impl Error + 'static) -> Self {
 +        Self {
 +            conf: Conf::default(),
 +            errors: vec![Box::new(error)],
 +            warnings: vec![],
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +struct ConfError(String);
 +
 +impl fmt::Display for ConfError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        <String as fmt::Display>::fmt(&self.0, f)
 +    }
 +}
 +
 +impl Error for ConfError {}
 +
 +fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
 +    Box::new(ConfError(s.into()))
 +}
 +
 +macro_rules! define_Conf {
 +    ($(
 +        $(#[doc = $doc:literal])+
 +        $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
 +        ($name:ident: $ty:ty = $default:expr),
 +    )*) => {
 +        /// Clippy lint configuration
 +        pub struct Conf {
 +            $($(#[doc = $doc])+ pub $name: $ty,)*
 +        }
 +
 +        mod defaults {
 +            $(pub fn $name() -> $ty { $default })*
 +        }
 +
 +        impl Default for Conf {
 +            fn default() -> Self {
 +                Self { $($name: defaults::$name(),)* }
 +            }
 +        }
 +
 +        impl<'de> Deserialize<'de> for TryConf {
 +            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
 +                deserializer.deserialize_map(ConfVisitor)
 +            }
 +        }
 +
 +        #[derive(Deserialize)]
 +        #[serde(field_identifier, rename_all = "kebab-case")]
 +        #[allow(non_camel_case_types)]
 +        enum Field { $($name,)* third_party, }
 +
 +        struct ConfVisitor;
 +
 +        impl<'de> Visitor<'de> for ConfVisitor {
 +            type Value = TryConf;
 +
 +            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                formatter.write_str("Conf")
 +            }
 +
 +            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
 +                let mut errors = Vec::new();
 +                let mut warnings = Vec::new();
 +                $(let mut $name = None;)*
 +                // could get `Field` here directly, but get `str` first for diagnostics
 +                while let Some(name) = map.next_key::<&str>()? {
 +                    match Field::deserialize(name.into_deserializer())? {
 +                        $(Field::$name => {
 +                            $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
 +                            match map.next_value() {
 +                                Err(e) => errors.push(conf_error(e.to_string())),
 +                                Ok(value) => match $name {
 +                                    Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
 +                                    None => {
 +                                        $name = Some(value);
 +                                        // $new_conf is the same as one of the defined `$name`s, so
 +                                        // this variable is defined in line 2 of this function.
 +                                        $(match $new_conf {
 +                                            Some(_) => errors.push(conf_error(concat!(
 +                                                "duplicate field `", stringify!($new_conf),
 +                                                "` (provided as `", stringify!($name), "`)"
 +                                            ))),
 +                                            None => $new_conf = $name.clone(),
 +                                        })?
 +                                    },
 +                                }
 +                            }
 +                        })*
 +                        // white-listed; ignore
 +                        Field::third_party => drop(map.next_value::<IgnoredAny>())
 +                    }
 +                }
 +                let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
 +                Ok(TryConf { conf, errors, warnings })
 +            }
 +        }
 +
 +        #[cfg(feature = "internal")]
 +        pub mod metadata {
 +            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 +
 +            macro_rules! wrap_option {
 +                () => (None);
 +                ($x:literal) => (Some($x));
 +            }
 +
 +            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 +                vec![
 +                    $(
 +                        {
 +                            let deprecation_reason = wrap_option!($($dep)?);
 +
 +                            ClippyConfiguration::new(
 +                                stringify!($name),
 +                                stringify!($ty),
 +                                format!("{:?}", super::defaults::$name()),
 +                                concat!($($doc, '\n',)*),
 +                                deprecation_reason,
 +                            )
 +                        },
 +                    )+
 +                ]
 +            }
 +        }
 +    };
 +}
 +
 +define_Conf! {
-     /// Suppress checking of the passed type names.
++    /// Lint: ARITHMETIC_SIDE_EFFECTS.
 +    ///
++    /// Suppress checking of the passed type names in all types of operations.
++    ///
++    /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
++    ///
++    /// #### Example
++    ///
++    /// ```toml
++    /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
++    /// ```
++    ///
++    /// #### Noteworthy
++    ///
++    /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
 +    (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
++    /// Lint: ARITHMETIC_SIDE_EFFECTS.
++    ///
++    /// Suppress checking of the passed type pair names in binary operations like addition or
++    /// multiplication.
++    ///
++    /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
++    /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
++    ///
++    /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
++    /// `["AnotherType", "SomeType"]`.
++    ///
++    /// #### Example
++    ///
++    /// ```toml
++    /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
++    /// ```
++    (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
++    /// Lint: ARITHMETIC_SIDE_EFFECTS.
++    ///
++    /// Suppress checking of the passed type names in unary operations like "negation" (`-`).
++    ///
++    /// #### Example
++    ///
++    /// ```toml
++    /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
++    /// ```
++    (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
 +    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
 +    ///
 +    /// Suppress lints whenever the suggested change would cause breakage for other crates.
 +    (avoid_breaking_exported_api: bool = true),
 +    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION.
 +    ///
 +    /// The minimum rust version that the project supports
 +    (msrv: Option<String> = None),
 +    /// DEPRECATED LINT: BLACKLISTED_NAME.
 +    ///
 +    /// Use the Disallowed Names lint instead
 +    #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
 +    (blacklisted_names: Vec<String> = Vec::new()),
 +    /// Lint: COGNITIVE_COMPLEXITY.
 +    ///
 +    /// The maximum cognitive complexity a function can have
 +    (cognitive_complexity_threshold: u64 = 25),
 +    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
 +    ///
 +    /// Use the Cognitive Complexity lint instead.
 +    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
 +    (cyclomatic_complexity_threshold: u64 = 25),
 +    /// Lint: DISALLOWED_NAMES.
 +    ///
 +    /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
 +    /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
 +    /// default configuration of Clippy. By default any configuration will replace the default value.
 +    (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
 +    /// Lint: DOC_MARKDOWN.
 +    ///
 +    /// 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
 +    /// default configuration of Clippy. By default any configuraction will replace the default value. For example:
 +    /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 +    /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 +    ///
 +    /// Default list:
 +    (doc_valid_idents: Vec<String> = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
 +    /// Lint: TOO_MANY_ARGUMENTS.
 +    ///
 +    /// The maximum number of argument a function or method can have
 +    (too_many_arguments_threshold: u64 = 7),
 +    /// Lint: TYPE_COMPLEXITY.
 +    ///
 +    /// The maximum complexity a type can have
 +    (type_complexity_threshold: u64 = 250),
 +    /// Lint: MANY_SINGLE_CHAR_NAMES.
 +    ///
 +    /// The maximum number of single char bindings a scope may have
 +    (single_char_binding_names_threshold: u64 = 4),
 +    /// Lint: BOXED_LOCAL, USELESS_VEC.
 +    ///
 +    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
 +    (too_large_for_stack: u64 = 200),
 +    /// Lint: ENUM_VARIANT_NAMES.
 +    ///
 +    /// The minimum number of enum variants for the lints about variant names to trigger
 +    (enum_variant_name_threshold: u64 = 3),
 +    /// Lint: LARGE_ENUM_VARIANT.
 +    ///
 +    /// The maximum size of an enum's variant to avoid box suggestion
 +    (enum_variant_size_threshold: u64 = 200),
 +    /// Lint: VERBOSE_BIT_MASK.
 +    ///
 +    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
 +    (verbose_bit_mask_threshold: u64 = 1),
 +    /// Lint: DECIMAL_LITERAL_REPRESENTATION.
 +    ///
 +    /// The lower bound for linting decimal literals
 +    (literal_representation_threshold: u64 = 16384),
 +    /// Lint: TRIVIALLY_COPY_PASS_BY_REF.
 +    ///
 +    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
 +    (trivial_copy_size_limit: Option<u64> = None),
 +    /// Lint: LARGE_TYPE_PASS_BY_MOVE.
 +    ///
 +    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
 +    (pass_by_value_size_limit: u64 = 256),
 +    /// Lint: TOO_MANY_LINES.
 +    ///
 +    /// The maximum number of lines a function or method can have
 +    (too_many_lines_threshold: u64 = 100),
 +    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
 +    ///
 +    /// The maximum allowed size for arrays on the stack
 +    (array_size_threshold: u64 = 512_000),
 +    /// Lint: VEC_BOX.
 +    ///
 +    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
 +    (vec_box_size_threshold: u64 = 4096),
 +    /// Lint: TYPE_REPETITION_IN_BOUNDS.
 +    ///
 +    /// The maximum number of bounds a trait can have to be linted
 +    (max_trait_bounds: u64 = 3),
 +    /// Lint: STRUCT_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool fields a struct can have
 +    (max_struct_bools: u64 = 3),
 +    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool parameters a function can have
 +    (max_fn_params_bools: u64 = 3),
 +    /// Lint: WILDCARD_IMPORTS.
 +    ///
 +    /// Whether to allow certain wildcard imports (prelude, super in tests).
 +    (warn_on_all_wildcard_imports: bool = false),
 +    /// Lint: DISALLOWED_MACROS.
 +    ///
 +    /// The list of disallowed macros, written as fully qualified paths.
 +    (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
 +    /// Lint: DISALLOWED_METHODS.
 +    ///
 +    /// The list of disallowed methods, written as fully qualified paths.
 +    (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
 +    /// Lint: DISALLOWED_TYPES.
 +    ///
 +    /// The list of disallowed types, written as fully qualified paths.
 +    (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
 +    /// Lint: UNREADABLE_LITERAL.
 +    ///
 +    /// Should the fraction of a decimal be linted to include separators.
 +    (unreadable_literal_lint_fractions: bool = true),
 +    /// Lint: UPPER_CASE_ACRONYMS.
 +    ///
 +    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
 +    (upper_case_acronyms_aggressive: bool = false),
 +    /// Lint: MANUAL_LET_ELSE.
 +    ///
 +    /// Whether the matches should be considered by the lint, and whether there should
 +    /// be filtering for common types.
 +    (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour =
 +        crate::manual_let_else::MatchLintBehaviour::WellKnownTypes),
 +    /// Lint: _CARGO_COMMON_METADATA.
 +    ///
 +    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
 +    (cargo_ignore_publish: bool = false),
 +    /// Lint: NONSTANDARD_MACRO_BRACES.
 +    ///
 +    /// Enforce the named macros always use the braces specified.
 +    ///
 +    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
 +    /// is could be used with a full path two `MacroMatcher`s have to be added one with the full path
 +    /// `crate_name::macro_name` and one with just the macro name.
 +    (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
 +    /// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
 +    ///
 +    /// The list of imports to always rename, a fully qualified path followed by the rename.
 +    (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
 +    /// Lint: DISALLOWED_SCRIPT_IDENTS.
 +    ///
 +    /// The list of unicode scripts allowed to be used in the scope.
 +    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
 +    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
 +    ///
 +    /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
 +    (enable_raw_pointer_heuristic_for_send: bool = true),
 +    /// Lint: INDEX_REFUTABLE_SLICE.
 +    ///
 +    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
 +    /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
 +    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
 +    (max_suggested_slice_pattern_length: u64 = 3),
 +    /// Lint: AWAIT_HOLDING_INVALID_TYPE
 +    (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
 +    /// Lint: LARGE_INCLUDE_FILE.
 +    ///
 +    /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
 +    (max_include_file_size: u64 = 1_000_000),
 +    /// Lint: EXPECT_USED.
 +    ///
 +    /// Whether `expect` should be allowed within `#[cfg(test)]`
 +    (allow_expect_in_tests: bool = false),
 +    /// Lint: UNWRAP_USED.
 +    ///
 +    /// Whether `unwrap` should be allowed in test cfg
 +    (allow_unwrap_in_tests: bool = false),
 +    /// Lint: DBG_MACRO.
 +    ///
 +    /// Whether `dbg!` should be allowed in test functions
 +    (allow_dbg_in_tests: bool = false),
 +    /// Lint: PRINT_STDOUT, PRINT_STDERR.
 +    ///
 +    /// Whether print macros (ex. `println!`) should be allowed in test functions
 +    (allow_print_in_tests: bool = false),
 +    /// Lint: RESULT_LARGE_ERR.
 +    ///
 +    /// The maximum size of the `Err`-variant in a `Result` returned from a function
 +    (large_error_threshold: u64 = 128),
 +    /// Lint: MUTABLE_KEY.
 +    ///
 +    /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
 +    /// for the generic parameters for determining interior mutability
 +    (ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()])),
 +    /// Lint: UNINLINED_FORMAT_ARGS.
 +    ///
 +    /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
 +    (allow_mixed_uninlined_format_args: bool = true),
++    /// Lint: INDEXING_SLICING
++    ///
++    /// Whether to suppress a restriction lint in constant code. In same
++    /// cases the restructured operation might not be unavoidable, as the
++    /// suggested counterparts are unavailable in constant code. This
++    /// configuration will cause restriction lints to trigger even
++    /// if no suggestion can be made.
++    (suppress_restriction_lint_in_const: bool = false),
 +}
 +
 +/// Search for the configuration file.
 +///
 +/// # Errors
 +///
 +/// Returns any unexpected filesystem error encountered when searching for the config file
 +pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
 +    /// Possible filename to search for.
 +    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
 +
 +    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
 +    // If neither of those exist, use ".".
 +    let mut current = env::var_os("CLIPPY_CONF_DIR")
 +        .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
 +        .map_or_else(|| PathBuf::from("."), PathBuf::from);
 +
 +    let mut found_config: Option<PathBuf> = None;
 +
 +    loop {
 +        for config_file_name in &CONFIG_FILE_NAMES {
 +            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
 +                match fs::metadata(&config_file) {
 +                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
 +                    Err(e) => return Err(e),
 +                    Ok(md) if md.is_dir() => {},
 +                    Ok(_) => {
 +                        // warn if we happen to find two config files #8323
 +                        if let Some(ref found_config_) = found_config {
 +                            eprintln!(
 +                                "Using config file `{}`\nWarning: `{}` will be ignored.",
 +                                found_config_.display(),
 +                                config_file.display(),
 +                            );
 +                        } else {
 +                            found_config = Some(config_file);
 +                        }
 +                    },
 +                }
 +            }
 +        }
 +
 +        if found_config.is_some() {
 +            return Ok(found_config);
 +        }
 +
 +        // If the current directory has no parent, we're done searching.
 +        if !current.pop() {
 +            return Ok(None);
 +        }
 +    }
 +}
 +
 +/// Read the `toml` configuration file.
 +///
 +/// In case of error, the function tries to continue as much as possible.
 +pub fn read(path: &Path) -> TryConf {
 +    let content = match fs::read_to_string(path) {
 +        Err(e) => return TryConf::from_error(e),
 +        Ok(content) => content,
 +    };
 +    match toml::from_str::<TryConf>(&content) {
 +        Ok(mut conf) => {
 +            extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
 +            extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
 +
 +            conf
 +        },
 +        Err(e) => TryConf::from_error(e),
 +    }
 +}
 +
 +fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
 +    if vec.contains(&"..".to_string()) {
 +        vec.extend(default.iter().map(ToString::to_string));
 +    }
 +}
 +
 +const SEPARATOR_WIDTH: usize = 4;
 +
 +// Check whether the error is "unknown field" and, if so, list the available fields sorted and at
 +// least one per line, more if `CLIPPY_TERMINAL_WIDTH` is set and allows it.
 +pub fn format_error(error: Box<dyn Error>) -> String {
 +    let s = error.to_string();
 +
 +    if_chain! {
 +        if error.downcast::<toml::de::Error>().is_ok();
 +        if let Some((prefix, mut fields, suffix)) = parse_unknown_field_message(&s);
 +        then {
 +            use fmt::Write;
 +
 +            fields.sort_unstable();
 +
 +            let (rows, column_widths) = calculate_dimensions(&fields);
 +
 +            let mut msg = String::from(prefix);
 +            for row in 0..rows {
 +                writeln!(msg).unwrap();
 +                for (column, column_width) in column_widths.iter().copied().enumerate() {
 +                    let index = column * rows + row;
 +                    let field = fields.get(index).copied().unwrap_or_default();
 +                    write!(
 +                        msg,
 +                        "{:SEPARATOR_WIDTH$}{field:column_width$}",
 +                        " "
 +                    )
 +                    .unwrap();
 +                }
 +            }
 +            write!(msg, "\n{suffix}").unwrap();
 +            msg
 +        } else {
 +            s
 +        }
 +    }
 +}
 +
 +// `parse_unknown_field_message` will become unnecessary if
 +// https://github.com/alexcrichton/toml-rs/pull/364 is merged.
 +fn parse_unknown_field_message(s: &str) -> Option<(&str, Vec<&str>, &str)> {
 +    // An "unknown field" message has the following form:
 +    //   unknown field `UNKNOWN`, expected one of `FIELD0`, `FIELD1`, ..., `FIELDN` at line X column Y
 +    //                                           ^^      ^^^^                     ^^
 +    if_chain! {
 +        if s.starts_with("unknown field");
 +        let slices = s.split("`, `").collect::<Vec<_>>();
 +        let n = slices.len();
 +        if n >= 2;
 +        if let Some((prefix, first_field)) = slices[0].rsplit_once(" `");
 +        if let Some((last_field, suffix)) = slices[n - 1].split_once("` ");
 +        then {
 +            let fields = iter::once(first_field)
 +                .chain(slices[1..n - 1].iter().copied())
 +                .chain(iter::once(last_field))
 +                .collect::<Vec<_>>();
 +            Some((prefix, fields, suffix))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
 +    let columns = env::var("CLIPPY_TERMINAL_WIDTH")
 +        .ok()
 +        .and_then(|s| <usize as FromStr>::from_str(&s).ok())
 +        .map_or(1, |terminal_width| {
 +            let max_field_width = fields.iter().map(|field| field.len()).max().unwrap();
 +            cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width))
 +        });
 +
 +    let rows = (fields.len() + (columns - 1)) / columns;
 +
 +    let column_widths = (0..columns)
 +        .map(|column| {
 +            if column < columns - 1 {
 +                (0..rows)
 +                    .map(|row| {
 +                        let index = column * rows + row;
 +                        let field = fields.get(index).copied().unwrap_or_default();
 +                        field.len()
 +                    })
 +                    .max()
 +                    .unwrap()
 +            } else {
 +                // Avoid adding extra space to the last column.
 +                0
 +            }
 +        })
 +        .collect::<Vec<_>>();
 +
 +    (rows, column_widths)
 +}
index 680935f2329e4e5037ffdf2c1f01022c962f3702,0000000000000000000000000000000000000000..9afe02c1e47da00cadc26e240f6e4d34d6fe99ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,108 -1,0 +1,108 @@@
- use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::def_path_res;
 +use clippy_utils::diagnostics::span_lint;
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::def::DefKind;
 +use rustc_hir::Item;
 +use rustc_hir_analysis::hir_ty_to_ty;
 +use rustc_lint::{LateContext, LateLintPass};
-         SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
-         SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
-         SimplifiedTypeGen::SliceSimplifiedType,
-         SimplifiedTypeGen::StrSimplifiedType,
++use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::Symbol;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks the paths module for invalid paths.
 +    ///
 +    /// ### Why is this bad?
 +    /// It indicates a bug in the code.
 +    ///
 +    /// ### Example
 +    /// None.
 +    pub INVALID_PATHS,
 +    internal,
 +    "invalid path"
 +}
 +
 +declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let local_def_id = &cx.tcx.parent_module(item.hir_id());
 +        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
 +        if_chain! {
 +            if mod_name.as_str() == "paths";
 +            if let hir::ItemKind::Const(ty, body_id) = item.kind;
 +            let ty = hir_ty_to_ty(cx.tcx, ty);
 +            if let ty::Array(el_ty, _) = &ty.kind();
 +            if let ty::Ref(_, el_ty, _) = &el_ty.kind();
 +            if el_ty.is_str();
 +            let body = cx.tcx.hir().body(body_id);
 +            let typeck_results = cx.tcx.typeck_body(body_id);
 +            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
 +            let path: Vec<&str> = path
 +                .iter()
 +                .map(|x| {
 +                    if let Constant::Str(s) = x {
 +                        s.as_str()
 +                    } else {
 +                        // We checked the type of the constant above
 +                        unreachable!()
 +                    }
 +                })
 +                .collect();
 +            if !check_path(cx, &path[..]);
 +            then {
 +                span_lint(cx, INVALID_PATHS, item.span, "invalid path");
 +            }
 +        }
 +    }
 +}
 +
 +// This is not a complete resolver for paths. It works on all the paths currently used in the paths
 +// module.  That's all it does and all it needs to do.
 +pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
 +    if !def_path_res(cx, path).is_empty() {
 +        return true;
 +    }
 +
 +    // Some implementations can't be found by `path_to_res`, particularly inherent
 +    // implementations of native types. Check lang items.
 +    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
 +    let lang_items = cx.tcx.lang_items();
 +    // This list isn't complete, but good enough for our current list of paths.
 +    let incoherent_impls = [
++        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
++        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
++        SimplifiedType::SliceSimplifiedType,
++        SimplifiedType::StrSimplifiedType,
 +    ]
 +    .iter()
 +    .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
 +    for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
 +        let lang_item_path = cx.get_def_path(item_def_id);
 +        if path_syms.starts_with(&lang_item_path) {
 +            if let [item] = &path_syms[lang_item_path.len()..] {
 +                if matches!(
 +                    cx.tcx.def_kind(item_def_id),
 +                    DefKind::Mod | DefKind::Enum | DefKind::Trait
 +                ) {
 +                    for child in cx.tcx.module_children(item_def_id) {
 +                        if child.ident.name == *item {
 +                            return true;
 +                        }
 +                    }
 +                } else {
 +                    for child in cx.tcx.associated_item_def_ids(item_def_id) {
 +                        if cx.tcx.item_name(*child) == *item {
 +                            return true;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
index fb9f4740ecc5003922077019e7c3c12e4d634e77,0000000000000000000000000000000000000000..ac6a566b9cd3ae5f208e9c4758a71c79f5867b50
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
- version = "0.1.67"
 +[package]
 +name = "clippy_utils"
++version = "0.1.68"
 +edition = "2021"
 +publish = false
 +
 +[dependencies]
 +arrayvec = { version = "0.7", default-features = false }
 +if_chain = "1.0"
 +itertools = "0.10.1"
 +rustc-semver = "1.1"
 +
 +[features]
 +deny-warnings = []
 +internal = []
 +
 +[package.metadata.rust-analyzer]
 +# This crate uses #[feature(rustc_private)]
 +rustc_private = true
index 652f8b4d3c56ef7109668aface5f83bf35cc8514,0000000000000000000000000000000000000000..43e2d1ec826c2343b9d6dea43c11ae3fe3789917
mode 100644,000000..100644
--- /dev/null
@@@ -1,2494 -1,0 +1,2494 @@@
-             kind: ItemKind::Const(..) | ItemKind::Static(..),
 +#![feature(array_chunks)]
 +#![feature(box_patterns)]
 +#![feature(control_flow_enum)]
 +#![feature(let_chains)]
 +#![feature(lint_reasons)]
 +#![feature(never_type)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
 +// warn on the same lints as `clippy_lints`
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// 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_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_typeck;
 +extern crate rustc_index;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_mir_dataflow;
 +extern crate rustc_parse_format;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +
 +#[macro_use]
 +pub mod sym_helper;
 +
 +pub mod ast_utils;
 +pub mod attrs;
 +mod check_proc_macro;
 +pub mod comparisons;
 +pub mod consts;
 +pub mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +pub mod macros;
 +pub mod mir;
 +pub mod msrvs;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod qualify_min_const_fn;
 +pub mod source;
 +pub mod str_utils;
 +pub mod sugg;
 +pub mod ty;
 +pub mod usage;
 +pub mod visitors;
 +
 +pub use self::attrs::*;
 +pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
 +pub use self::hir_utils::{
 +    both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
 +};
 +
 +use core::ops::ControlFlow;
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +use std::sync::OnceLock;
 +use std::sync::{Mutex, MutexGuard};
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, LitKind};
 +use rustc_ast::Attribute;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_data_structures::unhash::UnhashMap;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 +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,
 +    MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
 +    TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 +};
 +use rustc_lexer::{tokenize, TokenKind};
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::place::PlaceBase;
 +use rustc_middle::ty as rustc_ty;
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::binding::BindingMode;
 +use rustc_middle::ty::fast_reject::SimplifiedType::{
 +    ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
 +    PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 +};
 +use rustc_middle::ty::{
 +    layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture,
 +};
 +use rustc_middle::ty::{FloatTy, IntTy, UintTy};
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::SourceMap;
 +use rustc_span::sym;
 +use rustc_span::symbol::{kw, Ident, Symbol};
 +use rustc_span::Span;
 +use rustc_target::abi::Integer;
 +
 +use crate::consts::{constant, Constant};
 +use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
 +use crate::visitors::for_each_expr;
 +
 +#[macro_export]
 +macro_rules! extract_msrv_attr {
 +    ($context:ident) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
 +            let sess = rustc_lint::LintContext::sess(cx);
 +            self.msrv.enter_lint_attrs(sess, attrs);
 +        }
 +
 +        fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
 +            let sess = rustc_lint::LintContext::sess(cx);
 +            self.msrv.exit_lint_attrs(sess, attrs);
 +        }
 +    };
 +}
 +
 +/// If the given expression is a local binding, find the initializer expression.
 +/// If that initializer expression is another local binding, find its initializer again.
 +/// This process repeats as long as possible (but usually no more than once). Initializer
 +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
 +/// instead.
 +///
 +/// Examples:
 +/// ```
 +/// let abc = 1;
 +/// //        ^ output
 +/// let def = abc;
 +/// dbg!(def);
 +/// //   ^^^ input
 +///
 +/// // or...
 +/// let abc = 1;
 +/// let def = abc + 2;
 +/// //        ^^^^^^^ output
 +/// dbg!(def);
 +/// //   ^^^ input
 +/// ```
 +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
 +    while let Some(init) = path_to_local(expr)
 +        .and_then(|id| find_binding_init(cx, id))
 +        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
 +    {
 +        expr = init;
 +    }
 +    expr
 +}
 +
 +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
 +/// By only considering immutable bindings, we guarantee that the returned expression represents the
 +/// value of the binding wherever it is referenced.
 +///
 +/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
 +/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
 +/// canonical binding `HirId`.
 +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
 +    let hir = cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::Pat(pat)) = hir.find(hir_id);
 +        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
 +        let parent = hir.get_parent_node(hir_id);
 +        if let Some(Node::Local(local)) = hir.find(parent);
 +        then {
 +            return local.init;
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns `true` if the given `NodeId` is inside a constant context
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// if in_constant(cx, expr.hir_id) {
 +///     // Do something
 +/// }
 +/// ```
 +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,
 +    }
 +}
 +
 +/// Checks if a `Res` refers to a constructor of a `LangItem`
 +/// For example, use this to check whether a function call or a pattern is `Some(..)`.
 +pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
 +    if let Res::Def(DefKind::Ctor(..), id) = res
 +        && let Some(lang_id) = cx.tcx.lang_items().get(lang_item)
 +        && let Some(id) = cx.tcx.opt_parent(id)
 +    {
 +        id == lang_id
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool {
 +    if let Res::Def(DefKind::Ctor(..), id) = res
 +        && let Some(id) = cx.tcx.opt_parent(id)
 +    {
 +        cx.tcx.is_diagnostic_item(diag_item, id)
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Checks if a `QPath` resolves to a constructor of a diagnostic item.
 +pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool {
 +    if let QPath::Resolved(_, path) = qpath {
 +        if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
 +            return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id));
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if the `DefId` matches the given diagnostic item or it's constructor.
 +pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {
 +    let did = match cx.tcx.def_kind(did) {
 +        DefKind::Ctor(..) => cx.tcx.parent(did),
 +        // Constructors for types in external crates seem to have `DefKind::Variant`
 +        DefKind::Variant => match cx.tcx.opt_parent(did) {
 +            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
 +            _ => did,
 +        },
 +        _ => did,
 +    };
 +
 +    cx.tcx.is_diagnostic_item(item, did)
 +}
 +
 +/// Checks if the `DefId` matches the given `LangItem` or it's constructor.
 +pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {
 +    let did = match cx.tcx.def_kind(did) {
 +        DefKind::Ctor(..) => cx.tcx.parent(did),
 +        // Constructors for types in external crates seem to have `DefKind::Variant`
 +        DefKind::Variant => match cx.tcx.opt_parent(did) {
 +            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
 +            _ => did,
 +        },
 +        _ => did,
 +    };
 +
 +    cx.tcx.lang_items().get(item) == Some(did)
 +}
 +
 +pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
 +    matches!(
 +        expr.kind,
 +        ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr: None,
 +                ..
 +            },
 +            _
 +        ) | ExprKind::Tup([])
 +    )
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild(pat: &Pat<'_>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// 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 {
 +    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +    let trt_id = cx.tcx.trait_of_item(def_id);
 +    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 +}
 +
 +/// Checks if a method is defined in an impl of a diagnostic item
 +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +        if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +            return cx.tcx.is_diagnostic_item(diag_item, adt.did());
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if a method is in a diagnostic item trait
 +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
 +        return cx.tcx.is_diagnostic_item(diag_item, trait_did);
 +    }
 +    false
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    cx.typeck_results()
 +        .type_dependent_def_id(expr.hir_id)
 +        .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 +}
 +
 +/// Checks if the given expression is a path referring an item on the trait
 +/// that is marked with the given diagnostic item.
 +///
 +/// For checking method call expressions instead of path expressions, use
 +/// [`is_trait_method`].
 +///
 +/// For example, this can be used to find if an expression like `u64::default`
 +/// refers to an item of the trait `Default`, which is associated with the
 +/// `diag_item` of `sym::Default`.
 +pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    if let hir::ExprKind::Path(ref qpath) = expr.kind {
 +        cx.qpath_res(qpath, expr.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
 +    last_path_segment(qpath)
 +        .args
 +        .map_or(&[][..], |a| a.args)
 +        .iter()
 +        .filter_map(|a| match a {
 +            hir::GenericArg::Type(ty) => Some(*ty),
 +            _ => None,
 +        })
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `QPath` against a slice of segment string literals.
 +///
 +/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
 +/// `rustc_hir::QPath`.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_qpath(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 +    match *path {
 +        QPath::Resolved(_, path) => match_path(path, segments),
 +        QPath::TypeRelative(ty, segment) => match ty.kind {
 +            TyKind::Path(ref inner_path) => {
 +                if let [prefix @ .., end] = segments {
 +                    if match_qpath(inner_path, prefix) {
 +                        return segment.ident.name.as_str() == *end;
 +                    }
 +                }
 +                false
 +            },
 +            _ => false,
 +        },
 +        QPath::LangItem(..) => false,
 +    }
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 +///
 +/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
 +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
 +    path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
 +/// it matches the given lang item.
 +pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool {
 +    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id))
 +}
 +
 +/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
 +/// it matches the given diagnostic item.
 +pub fn is_path_diagnostic_item<'tcx>(
 +    cx: &LateContext<'_>,
 +    maybe_path: &impl MaybePath<'tcx>,
 +    diag_item: Symbol,
 +) -> bool {
 +    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `Path` against a slice of segment string literals.
 +///
 +/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
 +/// `rustc_hir::Path`.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// if match_path(&trait_ref.path, &paths::HASH) {
 +///     // This is the `std::hash::Hash` trait.
 +/// }
 +///
 +/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
 +///     // This is a `rustc_middle::lint::Lint`.
 +/// }
 +/// ```
 +pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// If the expression is a path to a local, returns the canonical `HirId` of the local.
 +pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
 +    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
 +        if let Res::Local(id) = path.res {
 +            return Some(id);
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns true if the expression is a path to a local with the specified `HirId`.
 +/// Use this function to see if an expression matches a function argument or a match binding.
 +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
 +    path_to_local(expr) == Some(id)
 +}
 +
 +pub trait MaybePath<'hir> {
 +    fn hir_id(&self) -> HirId;
 +    fn qpath_opt(&self) -> Option<&QPath<'hir>>;
 +}
 +
 +macro_rules! maybe_path {
 +    ($ty:ident, $kind:ident) => {
 +        impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
 +            fn hir_id(&self) -> HirId {
 +                self.hir_id
 +            }
 +            fn qpath_opt(&self) -> Option<&QPath<'hir>> {
 +                match &self.kind {
 +                    hir::$kind::Path(qpath) => Some(qpath),
 +                    _ => None,
 +                }
 +            }
 +        }
 +    };
 +}
 +maybe_path!(Expr, ExprKind);
 +maybe_path!(Pat, PatKind);
 +maybe_path!(Ty, TyKind);
 +
 +/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
 +pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
 +    match maybe_path.qpath_opt() {
 +        None => Res::Err,
 +        Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
 +    }
 +}
 +
 +/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
 +pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
 +    path_res(cx, maybe_path).opt_def_id()
 +}
 +
 +fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
 +    let ty = match name {
 +        "bool" => BoolSimplifiedType,
 +        "char" => CharSimplifiedType,
 +        "str" => StrSimplifiedType,
 +        "array" => ArraySimplifiedType,
 +        "slice" => SliceSimplifiedType,
 +        // FIXME: rustdoc documents these two using just `pointer`.
 +        //
 +        // Maybe this is something we should do here too.
 +        "const_ptr" => PtrSimplifiedType(Mutability::Not),
 +        "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
 +        "isize" => IntSimplifiedType(IntTy::Isize),
 +        "i8" => IntSimplifiedType(IntTy::I8),
 +        "i16" => IntSimplifiedType(IntTy::I16),
 +        "i32" => IntSimplifiedType(IntTy::I32),
 +        "i64" => IntSimplifiedType(IntTy::I64),
 +        "i128" => IntSimplifiedType(IntTy::I128),
 +        "usize" => UintSimplifiedType(UintTy::Usize),
 +        "u8" => UintSimplifiedType(UintTy::U8),
 +        "u16" => UintSimplifiedType(UintTy::U16),
 +        "u32" => UintSimplifiedType(UintTy::U32),
 +        "u64" => UintSimplifiedType(UintTy::U64),
 +        "u128" => UintSimplifiedType(UintTy::U128),
 +        "f32" => FloatSimplifiedType(FloatTy::F32),
 +        "f64" => FloatSimplifiedType(FloatTy::F64),
 +        _ => return [].iter().copied(),
 +    };
 +
 +    tcx.incoherent_impls(ty).iter().copied()
 +}
 +
 +fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
 +    match tcx.def_kind(def_id) {
 +        DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
 +            .module_children(def_id)
 +            .iter()
 +            .filter(|item| item.ident.name == name)
 +            .map(|child| child.res.expect_non_local())
 +            .collect(),
 +        DefKind::Impl => tcx
 +            .associated_item_def_ids(def_id)
 +            .iter()
 +            .copied()
 +            .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
 +            .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
 +            .collect(),
 +        _ => Vec::new(),
 +    }
 +}
 +
 +fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
 +    let hir = tcx.hir();
 +
 +    let root_mod;
 +    let item_kind = match hir.find_by_def_id(local_id) {
 +        Some(Node::Crate(r#mod)) => {
 +            root_mod = ItemKind::Mod(r#mod);
 +            &root_mod
 +        },
 +        Some(Node::Item(item)) => &item.kind,
 +        _ => return Vec::new(),
 +    };
 +
 +    let res = |ident: Ident, owner_id: OwnerId| {
 +        if ident.name == name {
 +            let def_id = owner_id.to_def_id();
 +            Some(Res::Def(tcx.def_kind(def_id), def_id))
 +        } else {
 +            None
 +        }
 +    };
 +
 +    match item_kind {
 +        ItemKind::Mod(r#mod) => r#mod
 +            .item_ids
 +            .iter()
 +            .filter_map(|&item_id| res(hir.item(item_id).ident, item_id.owner_id))
 +            .collect(),
 +        ItemKind::Impl(r#impl) => r#impl
 +            .items
 +            .iter()
 +            .filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id))
 +            .collect(),
 +        ItemKind::Trait(.., trait_item_refs) => trait_item_refs
 +            .iter()
 +            .filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id))
 +            .collect(),
 +        _ => Vec::new(),
 +    }
 +}
 +
 +fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
 +    if let Some(local_id) = def_id.as_local() {
 +        local_item_children_by_name(tcx, local_id, name)
 +    } else {
 +        non_local_item_children_by_name(tcx, def_id, name)
 +    }
 +}
 +
 +/// Resolves a def path like `std::vec::Vec`.
 +///
 +/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
 +/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
 +///
 +/// Also returns multiple results when there are mulitple paths under the same name e.g. `std::vec`
 +/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
 +///
 +/// This function is expensive and should be used sparingly.
 +pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
 +    fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ {
 +        tcx.crates(())
 +            .iter()
 +            .copied()
 +            .filter(move |&num| tcx.crate_name(num) == name)
 +            .map(CrateNum::as_def_id)
 +    }
 +
 +    let tcx = cx.tcx;
 +
 +    let (base, mut path) = match *path {
 +        [primitive] => {
 +            return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
 +        },
 +        [base, ref path @ ..] => (base, path),
 +        _ => return Vec::new(),
 +    };
 +
 +    let base_sym = Symbol::intern(base);
 +
 +    let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
 +        Some(LOCAL_CRATE.as_def_id())
 +    } else {
 +        None
 +    };
 +
 +    let starts = find_primitive_impls(tcx, base)
 +        .chain(find_crates(tcx, base_sym))
 +        .chain(local_crate)
 +        .map(|id| Res::Def(tcx.def_kind(id), id));
 +
 +    let mut resolutions: Vec<Res> = starts.collect();
 +
 +    while let [segment, rest @ ..] = path {
 +        path = rest;
 +        let segment = Symbol::intern(segment);
 +
 +        resolutions = resolutions
 +            .into_iter()
 +            .filter_map(|res| res.opt_def_id())
 +            .flat_map(|def_id| {
 +                // When the current def_id is e.g. `struct S`, check the impl items in
 +                // `impl S { ... }`
 +                let inherent_impl_children = tcx
 +                    .inherent_impls(def_id)
 +                    .iter()
 +                    .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
 +
 +                let direct_children = item_children_by_name(tcx, def_id, segment);
 +
 +                inherent_impl_children.chain(direct_children)
 +            })
 +            .collect();
 +    }
 +
 +    resolutions
 +}
 +
 +/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
 +pub fn def_path_def_ids(cx: &LateContext<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
 +    def_path_res(cx, path).into_iter().filter_map(|res| res.opt_def_id())
 +}
 +
 +/// Convenience function to get the `DefId` of a trait by path.
 +/// It could be a trait or trait alias.
 +///
 +/// This function is expensive and should be used sparingly.
 +pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 +    def_path_res(cx, path).into_iter().find_map(|res| match res {
 +        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
 +        _ => None,
 +    })
 +}
 +
 +/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 +///
 +/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
 +///
 +/// ```rust
 +/// struct Point(isize, isize);
 +///
 +/// impl std::ops::Add for Point {
 +///     type Output = Self;
 +///
 +///     fn add(self, other: Self) -> Self {
 +///         Point(0, 0)
 +///     }
 +/// }
 +/// ```
 +pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != hir::CRATE_OWNER_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id);
 +        if let hir::ItemKind::Impl(impl_) = &item.kind;
 +        then {
 +            return impl_.of_trait.as_ref();
 +        }
 +    }
 +    None
 +}
 +
 +/// This method will return tuple of projection stack and root of the expression,
 +/// used in `can_mut_borrow_both`.
 +///
 +/// For example, if `e` represents the `v[0].a.b[x]`
 +/// this method will return a tuple, composed of a `Vec`
 +/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
 +/// and an `Expr` for root of them, `v`
 +fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
 +    let mut result = vec![];
 +    let root = loop {
 +        match e.kind {
 +            ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
 +                result.push(e);
 +                e = ep;
 +            },
 +            _ => break e,
 +        };
 +    };
 +    result.reverse();
 +    (result, root)
 +}
 +
 +/// Gets the mutability of the custom deref adjustment, if any.
 +pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {
 +    cx.typeck_results()
 +        .expr_adjustments(e)
 +        .iter()
 +        .find_map(|a| match a.kind {
 +            Adjust::Deref(Some(d)) => Some(Some(d.mutbl)),
 +            Adjust::Deref(None) => None,
 +            _ => Some(None),
 +        })
 +        .and_then(|x| x)
 +}
 +
 +/// Checks if two expressions can be mutably borrowed simultaneously
 +/// and they aren't dependent on borrowing same thing twice
 +pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
 +    let (s1, r1) = projection_stack(e1);
 +    let (s2, r2) = projection_stack(e2);
 +    if !eq_expr_value(cx, r1, r2) {
 +        return true;
 +    }
 +    if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {
 +        return false;
 +    }
 +
 +    for (x1, x2) in s1.iter().zip(s2.iter()) {
 +        if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {
 +            return false;
 +        }
 +
 +        match (&x1.kind, &x2.kind) {
 +            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
 +                if i1 != i2 {
 +                    return true;
 +                }
 +            },
 +            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
 +                if !eq_expr_value(cx, i1, i2) {
 +                    return false;
 +                }
 +            },
 +            _ => return false,
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
 +/// constructor from the std library
 +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
 +    let std_types_symbols = &[
 +        sym::Vec,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::HashMap,
 +        sym::BTreeMap,
 +        sym::HashSet,
 +        sym::BTreeSet,
 +        sym::BinaryHeap,
 +    ];
 +
 +    if let QPath::TypeRelative(_, method) = path {
 +        if method.ident.name == sym::new {
 +            if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +                if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +                    return std_types_symbols.iter().any(|&symbol| {
 +                        cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
 +                    });
 +                }
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// Return true if the expr is equal to `Default::default` when evaluated.
 +pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
 +        if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
 +        if is_diag_trait_item(cx, repl_def_id, sym::Default)
 +            || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
 +        then { true } else { false }
 +    }
 +}
 +
 +/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
 +/// It doesn't cover all cases, for example indirect function calls (some of std
 +/// functions are supported) but it is the best we have.
 +pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    match &e.kind {
 +        ExprKind::Lit(lit) => match lit.node {
 +            LitKind::Bool(false) | LitKind::Int(0, _) => true,
 +            LitKind::Str(s, _) => s.is_empty(),
 +            _ => false,
 +        },
 +        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 LitKind::Int(v, _) = const_lit.node;
 +            if v <= 32 && is_default_equivalent(cx, x);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
 +        ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func),
 +        ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg),
 +        ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
 +        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
 +        _ => false,
 +    }
 +}
 +
 +fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
 +    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind &&
 +        seg.ident.name == sym::from
 +    {
 +        match arg.kind {
 +            ExprKind::Lit(hir::Lit {
 +                node: LitKind::Str(ref sym, _),
 +                ..
 +            }) => 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 &&
 +                    let LitKind::Int(v, _) = const_lit.node
 +                {
 +                        return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
 +                }
 +            }
 +            _ => (),
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if the top level expression can be moved into a closure as is.
 +/// Currently checks for:
 +/// * Break/Continue outside the given loop HIR ids.
 +/// * Yield/Return statements.
 +/// * Inline assembly.
 +/// * Usages of a field of a local where the type of the local can be partially moved.
 +///
 +/// For example, given the following function:
 +///
 +/// ```
 +/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
 +///     for item in iter {
 +///         let s = item.1;
 +///         if item.0 > 10 {
 +///             continue;
 +///         } else {
 +///             s.clear();
 +///         }
 +///     }
 +/// }
 +/// ```
 +///
 +/// When called on the expression `item.0` this will return false unless the local `item` is in the
 +/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
 +/// isn't always safe to move into a closure when only a single field is needed.
 +///
 +/// When called on the `continue` expression this will return false unless the outer loop expression
 +/// is in the `loop_ids` set.
 +///
 +/// Note that this check is not recursive, so passing the `if` expression will always return true
 +/// even though sub-expressions might return false.
 +pub fn can_move_expr_to_closure_no_visit<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    loop_ids: &[HirId],
 +    ignore_locals: &HirIdSet,
 +) -> bool {
 +    match expr.kind {
 +        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
 +        | ExprKind::Continue(Destination { target_id: Ok(id), .. })
 +            if loop_ids.contains(&id) =>
 +        {
 +            true
 +        },
 +        ExprKind::Break(..)
 +        | ExprKind::Continue(_)
 +        | ExprKind::Ret(_)
 +        | ExprKind::Yield(..)
 +        | ExprKind::InlineAsm(_) => false,
 +        // Accessing a field of a local value can only be done if the type isn't
 +        // partially moved.
 +        ExprKind::Field(
 +            &Expr {
 +                hir_id,
 +                kind:
 +                    ExprKind::Path(QPath::Resolved(
 +                        _,
 +                        Path {
 +                            res: Res::Local(local_id),
 +                            ..
 +                        },
 +                    )),
 +                ..
 +            },
 +            _,
 +        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
 +            // TODO: check if the local has been partially moved. Assume it has for now.
 +            false
 +        },
 +        _ => true,
 +    }
 +}
 +
 +/// How a local is captured by a closure
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum CaptureKind {
 +    Value,
 +    Ref(Mutability),
 +}
 +impl CaptureKind {
 +    pub fn is_imm_ref(self) -> bool {
 +        self == Self::Ref(Mutability::Not)
 +    }
 +}
 +impl std::ops::BitOr for CaptureKind {
 +    type Output = Self;
 +    fn bitor(self, rhs: Self) -> Self::Output {
 +        match (self, rhs) {
 +            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
 +            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
 +            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
 +            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
 +        }
 +    }
 +}
 +impl std::ops::BitOrAssign for CaptureKind {
 +    fn bitor_assign(&mut self, rhs: Self) {
 +        *self = *self | rhs;
 +    }
 +}
 +
 +/// Given an expression referencing a local, determines how it would be captured in a closure.
 +/// Note as this will walk up to parent expressions until the capture can be determined it should
 +/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
 +/// function argument (other than a receiver).
 +pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
 +    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
 +        let mut capture = CaptureKind::Ref(Mutability::Not);
 +        pat.each_binding_or_first(&mut |_, id, span, _| match cx
 +            .typeck_results()
 +            .extract_binding_mode(cx.sess(), id, span)
 +            .unwrap()
 +        {
 +            BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
 +                capture = CaptureKind::Value;
 +            },
 +            BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
 +                capture = CaptureKind::Ref(Mutability::Mut);
 +            },
 +            _ => (),
 +        });
 +        capture
 +    }
 +
 +    debug_assert!(matches!(
 +        e.kind,
 +        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
 +    ));
 +
 +    let mut child_id = e.hir_id;
 +    let mut capture = CaptureKind::Value;
 +    let mut capture_expr_ty = e;
 +
 +    for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
 +        if let [
 +            Adjustment {
 +                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
 +                target,
 +            },
 +            ref adjust @ ..,
 +        ] = *cx
 +            .typeck_results()
 +            .adjustments()
 +            .get(child_id)
 +            .map_or(&[][..], |x| &**x)
 +        {
 +            if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
 +                *adjust.last().map_or(target, |a| a.target).kind()
 +            {
 +                return CaptureKind::Ref(mutability);
 +            }
 +        }
 +
 +        match parent {
 +            Node::Expr(e) => match e.kind {
 +                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
 +                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
 +                ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
 +                    return CaptureKind::Ref(Mutability::Mut);
 +                },
 +                ExprKind::Field(..) => {
 +                    if capture == CaptureKind::Value {
 +                        capture_expr_ty = e;
 +                    }
 +                },
 +                ExprKind::Let(let_expr) => {
 +                    let mutability = match pat_capture_kind(cx, let_expr.pat) {
 +                        CaptureKind::Value => Mutability::Not,
 +                        CaptureKind::Ref(m) => m,
 +                    };
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                ExprKind::Match(_, arms, _) => {
 +                    let mut mutability = Mutability::Not;
 +                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
 +                        match capture {
 +                            CaptureKind::Value => break,
 +                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
 +                            CaptureKind::Ref(Mutability::Not) => (),
 +                        }
 +                    }
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                _ => break,
 +            },
 +            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
 +                CaptureKind::Value => break,
 +                capture @ CaptureKind::Ref(_) => return capture,
 +            },
 +            _ => break,
 +        }
 +
 +        child_id = parent_id;
 +    }
 +
 +    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
 +        // Copy types are never automatically captured by value.
 +        CaptureKind::Ref(Mutability::Not)
 +    } else {
 +        capture
 +    }
 +}
 +
 +/// Checks if the expression can be moved into a closure as is. This will return a list of captures
 +/// if so, otherwise, `None`.
 +pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
 +    struct V<'cx, 'tcx> {
 +        cx: &'cx LateContext<'tcx>,
 +        // Stack of potential break targets contained in the expression.
 +        loops: Vec<HirId>,
 +        /// Local variables created in the expression. These don't need to be captured.
 +        locals: HirIdSet,
 +        /// Whether this expression can be turned into a closure.
 +        allow_closure: bool,
 +        /// Locals which need to be captured, and whether they need to be by value, reference, or
 +        /// mutable reference.
 +        captures: HirIdMap<CaptureKind>,
 +    }
 +    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
 +        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +            if !self.allow_closure {
 +                return;
 +            }
 +
 +            match e.kind {
 +                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
 +                    if !self.locals.contains(&l) {
 +                        let cap = capture_local_usage(self.cx, e);
 +                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
 +                    }
 +                },
 +                ExprKind::Closure { .. } => {
 +                    let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id);
 +                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
 +                        let local_id = match capture.place.base {
 +                            PlaceBase::Local(id) => id,
 +                            PlaceBase::Upvar(var) => var.var_path.hir_id,
 +                            _ => continue,
 +                        };
 +                        if !self.locals.contains(&local_id) {
 +                            let capture = match capture.info.capture_kind {
 +                                UpvarCapture::ByValue => CaptureKind::Value,
 +                                UpvarCapture::ByRef(kind) => match kind {
 +                                    BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
 +                                    BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
 +                                        CaptureKind::Ref(Mutability::Mut)
 +                                    },
 +                                },
 +                            };
 +                            self.captures
 +                                .entry(local_id)
 +                                .and_modify(|e| *e |= capture)
 +                                .or_insert(capture);
 +                        }
 +                    }
 +                },
 +                ExprKind::Loop(b, ..) => {
 +                    self.loops.push(e.hir_id);
 +                    self.visit_block(b);
 +                    self.loops.pop();
 +                },
 +                _ => {
 +                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
 +                    walk_expr(self, e);
 +                },
 +            }
 +        }
 +
 +        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
 +            p.each_binding_or_first(&mut |_, id, _, _| {
 +                self.locals.insert(id);
 +            });
 +        }
 +    }
 +
 +    let mut v = V {
 +        cx,
 +        allow_closure: true,
 +        loops: Vec::new(),
 +        locals: HirIdSet::default(),
 +        captures: HirIdMap::default(),
 +    };
 +    v.visit_expr(expr);
 +    v.allow_closure.then_some(v.captures)
 +}
 +
 +/// Arguments of a method: the receiver and all the additional arguments.
 +pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
 +
 +/// Returns the method names and argument list of nested method call expressions that make up
 +/// `expr`. method/span lists are sorted with the most recent call first.
 +pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
 +    let mut method_names = Vec::with_capacity(max_depth);
 +    let mut arg_lists = Vec::with_capacity(max_depth);
 +    let mut spans = Vec::with_capacity(max_depth);
 +
 +    let mut current = expr;
 +    for _ in 0..max_depth {
 +        if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
 +            if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
 +                break;
 +            }
 +            method_names.push(path.ident.name);
 +            arg_lists.push((*receiver, &**args));
 +            spans.push(path.ident.span);
 +            current = receiver;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    (method_names, arg_lists, spans)
 +}
 +
 +/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 +///
 +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
 +/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 +/// containing the `Expr`s for
 +/// `.bar()` and `.baz()`
 +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
 +    let mut current = expr;
 +    let mut matched = Vec::with_capacity(methods.len());
 +    for method_name in methods.iter().rev() {
 +        // method chains are stored last -> first
 +        if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
 +            if path.ident.name.as_str() == *method_name {
 +                if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
 +                    return None;
 +                }
 +                matched.push((receiver, args)); // build up `matched` backwards
 +                current = receiver; // go to parent expression
 +            } else {
 +                return None;
 +            }
 +        } else {
 +            return None;
 +        }
 +    }
 +    // Reverse `matched` so that it is in the same order as `methods`.
 +    matched.reverse();
 +    Some(matched)
 +}
 +
 +/// Returns `true` if the provided `def_id` is an entrypoint to a program.
 +pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    cx.tcx
 +        .entry_fn(())
 +        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 +}
 +
 +/// Returns `true` if the expression is in the program's `#[panic_handler]`.
 +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    let parent = cx.tcx.hir().get_parent_item(e.hir_id);
 +    Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()
 +}
 +
 +/// Gets the name of the item the expression is in, if available.
 +pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
 +    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
 +    match cx.tcx.hir().find_by_def_id(parent_id) {
 +        Some(
 +            Node::Item(Item { ident, .. })
 +            | Node::TraitItem(TraitItem { ident, .. })
 +            | Node::ImplItem(ImplItem { ident, .. }),
 +        ) => Some(ident.name),
 +        _ => None,
 +    }
 +}
 +
 +pub struct ContainsName {
 +    pub name: Symbol,
 +    pub result: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ContainsName {
 +    fn visit_name(&mut self, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +}
 +
 +/// Checks if an `Expr` contains a certain name.
 +pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
 +    let mut cn = ContainsName { name, result: false };
 +    cn.visit_expr(expr);
 +    cn.result
 +}
 +
 +/// Returns `true` if `expr` contains a return expression
 +pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    for_each_expr(expr, |e| {
 +        if matches!(e.kind, hir::ExprKind::Ret(..)) {
 +            ControlFlow::Break(())
 +        } else {
 +            ControlFlow::Continue(())
 +        }
 +    })
 +    .is_some()
 +}
 +
 +/// Gets the parent node, if any.
 +pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
 +    tcx.hir().parent_iter(id).next().map(|(_, node)| node)
 +}
 +
 +/// Gets the parent expression, if any –- this is useful to constrain a lint.
 +pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    get_parent_expr_for_hir(cx, e.hir_id)
 +}
 +
 +/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
 +/// constraint lints
 +pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
 +    match get_parent_node(cx.tcx, hir_id) {
 +        Some(Node::Expr(parent)) => Some(parent),
 +        _ => None,
 +    }
 +}
 +
 +pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
 +    let map = &cx.tcx.hir();
 +    let enclosing_node = map
 +        .get_enclosing_scope(hir_id)
 +        .and_then(|enclosing_id| map.find(enclosing_id));
 +    enclosing_node.and_then(|node| match node {
 +        Node::Block(block) => Some(block),
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(_, _, eid),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(_, eid),
 +            ..
 +        }) => match cx.tcx.hir().body(eid).value.kind {
 +            ExprKind::Block(block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Gets the loop or closure enclosing the given expression, if any.
 +pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &Expr<'_>,
 +) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
 +        match node {
 +            Node::Expr(e) => match e.kind {
 +                ExprKind::Closure { .. } => {
 +                    if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
 +                        && subs.as_closure().kind() == ClosureKind::FnOnce
 +                    {
 +                        continue;
 +                    }
 +                    let is_once = walk_to_expr_usage(cx, e, |node, id| {
 +                        let Node::Expr(e) = node else {
 +                            return None;
 +                        };
 +                        match e.kind {
 +                            ExprKind::Call(f, _) if f.hir_id == id => Some(()),
 +                            ExprKind::Call(f, args) => {
 +                                let i = args.iter().position(|arg| arg.hir_id == id)?;
 +                                let sig = expr_sig(cx, f)?;
 +                                let predicates = sig
 +                                    .predicates_id()
 +                                    .map_or(cx.param_env, |id| cx.tcx.param_env(id))
 +                                    .caller_bounds();
 +                                sig.input(i).and_then(|ty| {
 +                                    ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
 +                                })
 +                            },
 +                            ExprKind::MethodCall(_, receiver, args, _) => {
 +                                let i = std::iter::once(receiver)
 +                                    .chain(args.iter())
 +                                    .position(|arg| arg.hir_id == id)?;
 +                                let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
 +                                let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
 +                                ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
 +                            },
 +                            _ => None,
 +                        }
 +                    })
 +                    .is_some();
 +                    if !is_once {
 +                        return Some(e);
 +                    }
 +                },
 +                ExprKind::Loop(..) => return Some(e),
 +                _ => (),
 +            },
 +            Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
 +            _ => break,
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets the parent node if it's an impl block.
 +pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
 +    match tcx.hir().parent_iter(id).next() {
 +        Some((
 +            _,
 +            Node::Item(Item {
 +                kind: ItemKind::Impl(imp),
 +                ..
 +            }),
 +        )) => Some(imp),
 +        _ => None,
 +    }
 +}
 +
 +/// Removes blocks around an expression, only if the block contains just one expression
 +/// and no statements. Unsafe blocks are not removed.
 +///
 +/// Examples:
 +///  * `{}`               -> `{}`
 +///  * `{ x }`            -> `x`
 +///  * `{{ x }}`          -> `x`
 +///  * `{ x; }`           -> `{ x; }`
 +///  * `{ x; y }`         -> `{ x; y }`
 +///  * `{ unsafe { x } }` -> `unsafe { x }`
 +pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
 +    while let ExprKind::Block(
 +        Block {
 +            stmts: [],
 +            expr: Some(inner),
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        },
 +        _,
 +    ) = expr.kind
 +    {
 +        expr = inner;
 +    }
 +    expr
 +}
 +
 +/// Removes blocks around an expression, only if the block contains just one expression
 +/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
 +///
 +/// Examples:
 +///  * `{}`               -> `{}`
 +///  * `{ x }`            -> `x`
 +///  * `{ x; }`           -> `x`
 +///  * `{{ x; }}`         -> `x`
 +///  * `{ x; y }`         -> `{ x; y }`
 +///  * `{ unsafe { x } }` -> `unsafe { x }`
 +pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
 +    while let ExprKind::Block(
 +        Block {
 +            stmts: [],
 +            expr: Some(inner),
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        }
 +        | Block {
 +            stmts:
 +                [
 +                    Stmt {
 +                        kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
 +                        ..
 +                    },
 +                ],
 +            expr: None,
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        },
 +        _,
 +    ) = expr.kind
 +    {
 +        expr = inner;
 +    }
 +    expr
 +}
 +
 +/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
 +pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    let mut iter = tcx.hir().parent_iter(expr.hir_id);
 +    match iter.next() {
 +        Some((
 +            _,
 +            Node::Expr(Expr {
 +                kind: ExprKind::If(_, _, Some(else_expr)),
 +                ..
 +            }),
 +        )) => else_expr.hir_id == expr.hir_id,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks whether the given expression is a constant integer of the given value.
 +/// unlike `is_integer_literal`, this version does const folding
 +pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
 +    if is_integer_literal(e, value) {
 +        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) {
 +        return value == v;
 +    }
 +    false
 +}
 +
 +/// 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 LitKind::Int(v, _) = spanned.node {
 +            return v == value;
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if the given `Expr` has been coerced before.
 +///
 +/// Examples of coercions can be found in the Nomicon at
 +/// <https://doc.rust-lang.org/nomicon/coercions.html>.
 +///
 +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for
 +/// more information on adjustments and coercions.
 +pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    cx.typeck_results().adjustments().get(e.hir_id).is_some()
 +}
 +
 +/// Returns the pre-expansion span if this comes from an expansion of the
 +/// macro `name`.
 +/// See also [`is_direct_expn_of`].
 +#[must_use]
 +pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 +    loop {
 +        if span.from_expansion() {
 +            let data = span.ctxt().outer_expn_data();
 +            let new_span = data.call_site;
 +
 +            if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +                if mac_name.as_str() == name {
 +                    return Some(new_span);
 +                }
 +            }
 +
 +            span = new_span;
 +        } else {
 +            return None;
 +        }
 +    }
 +}
 +
 +/// Returns the pre-expansion span if the span directly comes from an expansion
 +/// of the macro `name`.
 +/// The difference with [`is_expn_of`] is that in
 +/// ```rust
 +/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
 +/// # macro_rules! bar { ($e:expr) => { $e } }
 +/// foo!(bar!(42));
 +/// ```
 +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 +/// from `bar!` by `is_direct_expn_of`.
 +#[must_use]
 +pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 +    if span.from_expansion() {
 +        let data = span.ctxt().outer_expn_data();
 +        let new_span = data.call_site;
 +
 +        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +            if mac_name.as_str() == name {
 +                return Some(new_span);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Convenience function to get the return type of a function.
 +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
 +    cx.tcx.erase_late_bound_regions(ret_ty)
 +}
 +
 +/// Convenience function to get the nth argument type of a function.
 +pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
 +    cx.tcx.erase_late_bound_regions(arg)
 +}
 +
 +/// Checks if an expression is constructing a tuple-like enum variant or struct
 +pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(fun, _) = expr.kind {
 +        if let ExprKind::Path(ref qp) = fun.kind {
 +            let res = cx.qpath_res(qp, fun.hir_id);
 +            return match res {
 +                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
 +                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
 +                _ => false,
 +            };
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if a pattern is refutable.
 +// TODO: should be implemented using rustc/mir_build/thir machinery
 +pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 +    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
 +        matches!(
 +            cx.qpath_res(qpath, id),
 +            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
 +        )
 +    }
 +
 +    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
 +        i.into_iter().any(|pat| is_refutable(cx, pat))
 +    }
 +
 +    match pat.kind {
 +        PatKind::Wild => false,
 +        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
 +        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
 +        PatKind::Lit(..) | PatKind::Range(..) => true,
 +        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
 +        PatKind::Or(pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats)
 +        },
 +        PatKind::Tuple(pats, _) => are_refutable(cx, pats),
 +        PatKind::Struct(ref qpath, fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
 +        PatKind::Slice(head, middle, tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind() {
 +                rustc_ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
 +/// the function once on the given pattern.
 +pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
 +    if let PatKind::Or(pats) = pat.kind {
 +        pats.iter().for_each(f);
 +    } else {
 +        f(pat);
 +    }
 +}
 +
 +pub fn is_self(slf: &Param<'_>) -> bool {
 +    if let PatKind::Binding(.., name, _) = slf.pat.kind {
 +        name.name == kw::SelfLower
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
 +        if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
 +    (0..decl.inputs.len()).map(move |i| &body.params[i])
 +}
 +
 +/// Checks if a given expression is a match expression expanded from the `?`
 +/// operator or the `try` macro.
 +pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
 +            if ddpos.as_opt_usize().is_none();
 +            if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if path_to_local_id(arm.body, hir_id);
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr)
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
 +        if *source == MatchSource::TryDesugar {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
 +            then {
 +                return Some(expr);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Returns `true` if the lint is allowed in the current context. This is useful for
 +/// skipping long running code when it's unnecessary
 +///
 +/// This function should check the lint level for the same node, that the lint will
 +/// be emitted at. If the information is buffered to be emitted at a later point, please
 +/// make sure to use `span_lint_hir` functions to emit the lint. This ensures that
 +/// expectations at the checked nodes will be fulfilled.
 +pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
 +    while let PatKind::Ref(subpat, _) = pat.kind {
 +        pat = subpat;
 +    }
 +    pat
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
 +    Integer::from_int_ty(&tcx, ity).size().bits()
 +}
 +
 +#[expect(clippy::cast_possible_wrap)]
 +/// Turn a constant int byte representation into an i128
 +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as i128) << amt) >> amt
 +}
 +
 +#[expect(clippy::cast_sign_loss)]
 +/// clip unused bytes
 +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as u128) << amt) >> amt
 +}
 +
 +/// clip unused bytes
 +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
 +    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +pub fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(symbol))
 +}
 +
 +pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +    has_attr(cx.tcx.hir().attrs(hir_id), sym::repr)
 +}
 +
 +pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
 +    let map = &tcx.hir();
 +    let mut prev_enclosing_node = None;
 +    let mut enclosing_node = node;
 +    while Some(enclosing_node) != prev_enclosing_node {
 +        if has_attr(map.attrs(enclosing_node), symbol) {
 +            return true;
 +        }
 +        prev_enclosing_node = Some(enclosing_node);
 +        enclosing_node = map.get_parent_item(enclosing_node).into();
 +    }
 +
 +    false
 +}
 +
 +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
 +    any_parent_has_attr(tcx, node, sym::automatically_derived)
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
 +/// ```
 +/// This function is deprecated. Use [`match_function_call_with_def_id`].
 +pub fn match_function_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    path: &[&str],
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        if match_def_path(cx, fun_def_id, path);
 +        then {
 +            return Some(args);
 +        }
 +    };
 +    None
 +}
 +
 +pub fn match_function_call_with_def_id<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    fun_def_id: DefId,
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id);
 +        then {
 +            return Some(args);
 +        }
 +    };
 +    None
 +}
 +
 +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 +/// any.
 +///
 +/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
 +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
 +    let search_path = cx.get_def_path(did);
 +    paths
 +        .iter()
 +        .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
 +}
 +
 +/// Checks if the given `DefId` matches the path.
 +pub fn match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool {
 +    // We should probably move to Symbols in Clippy as well rather than interning every time.
 +    let path = cx.get_def_path(did);
 +    syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
 +}
 +
 +/// Checks if the given `DefId` matches the `libc` item.
 +pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
 +    let path = cx.get_def_path(did);
 +    // libc is meant to be used as a flat list of names, but they're all actually defined in different
 +    // modules based on the target platform. Ignore everything but crate name and the item name.
 +    path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
 +}
 +
 +/// Returns the list of condition expressions and the list of blocks in a
 +/// sequence of `if/else`.
 +/// E.g., this returns `([a, b], [c, d, e])` for the expression
 +/// `if a { c } else if b { d } else { e }`.
 +pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
 +    let mut conds = Vec::new();
 +    let mut blocks: Vec<&Block<'_>> = Vec::new();
 +
 +    while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
 +        conds.push(cond);
 +        if let ExprKind::Block(block, _) = then.kind {
 +            blocks.push(block);
 +        } else {
 +            panic!("ExprKind::If node is not an ExprKind::Block");
 +        }
 +
 +        if let Some(else_expr) = r#else {
 +            expr = else_expr;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    // final `else {..}`
 +    if !blocks.is_empty() {
 +        if let ExprKind::Block(block, _) = expr.kind {
 +            blocks.push(block);
 +        }
 +    }
 +
 +    (conds, blocks)
 +}
 +
 +/// Checks if the given function kind is an async function.
 +pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 +    match kind {
 +        FnKind::ItemFn(_, _, header) => header.asyncness == IsAsync::Async,
 +        FnKind::Method(_, sig) => sig.header.asyncness == IsAsync::Async,
 +        FnKind::Closure => false,
 +    }
 +}
 +
 +/// Peels away all the compiler generated code surrounding the body of an async function,
 +pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(
 +        _,
 +        &[
 +            Expr {
 +                kind: ExprKind::Closure(&Closure { body, .. }),
 +                ..
 +            },
 +        ],
 +    ) = body.value.kind
 +    {
 +        if let ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr:
 +                    Some(Expr {
 +                        kind: ExprKind::DropTemps(expr),
 +                        ..
 +                    }),
 +                ..
 +            },
 +            _,
 +        ) = tcx.hir().body(body).value.kind
 +        {
 +            return Some(expr);
 +        }
 +    };
 +    None
 +}
 +
 +// check if expr is calling method or function with #[must_use] attribute
 +pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let did = match expr.kind {
 +        ExprKind::Call(path, _) => if_chain! {
 +            if let ExprKind::Path(ref qpath) = path.kind;
 +            if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
 +            then {
 +                Some(did)
 +            } else {
 +                None
 +            }
 +        },
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        _ => None,
 +    };
 +
 +    did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
 +}
 +
 +/// Checks if an expression represents the identity function
 +/// Only examines closures and `std::convert::identity`
 +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
 +    /// * `|x| x`
 +    /// * `|x| return x`
 +    /// * `|x| { return x }`
 +    /// * `|x| { return x; }`
 +    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 +        let id = if_chain! {
 +            if let [param] = func.params;
 +            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
 +            then {
 +                id
 +            } else {
 +                return false;
 +            }
 +        };
 +
 +        let mut expr = func.value;
 +        loop {
 +            match expr.kind {
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
 +                | ExprKind::Ret(Some(e)) => expr = e,
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
 +                    if_chain! {
 +                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
 +                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
 +                        then {
 +                            expr = ret_val;
 +                        } else {
 +                            return false;
 +                        }
 +                    }
 +                },
 +                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
 +            }
 +        }
 +    }
 +
 +    match expr.kind {
 +        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
 +        _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
 +    }
 +}
 +
 +/// Gets the node where an expression is either used, or it's type is unified with another branch.
 +/// Returns both the node and the `HirId` of the closest child node.
 +pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
 +    let mut child_id = expr.hir_id;
 +    let mut iter = tcx.hir().parent_iter(child_id);
 +    loop {
 +        match iter.next() {
 +            None => break None,
 +            Some((id, Node::Block(_))) => child_id = id,
 +            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
 +            Some((_, Node::Expr(expr))) => match expr.kind {
 +                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
 +                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
 +                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
 +                _ => break Some((Node::Expr(expr), child_id)),
 +            },
 +            Some((_, node)) => break Some((node, child_id)),
 +        }
 +    }
 +}
 +
 +/// Checks if the result of an expression is used, or it's type is unified with another branch.
 +pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    !matches!(
 +        get_expr_use_or_unification_node(tcx, expr),
 +        None | Some((
 +            Node::Stmt(Stmt {
 +                kind: StmtKind::Expr(_)
 +                    | StmtKind::Semi(_)
 +                    | StmtKind::Local(Local {
 +                        pat: Pat {
 +                            kind: PatKind::Wild,
 +                            ..
 +                        },
 +                        ..
 +                    }),
 +                ..
 +            }),
 +            _
 +        ))
 +    )
 +}
 +
 +/// Checks if the expression is the final expression returned from a block.
 +pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
 +}
 +
 +pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
 +    if !is_no_std_crate(cx) {
 +        Some("std")
 +    } else if !is_no_core_crate(cx) {
 +        Some("core")
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref normal) = attr.kind {
 +            normal.item.path == sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref normal) = attr.kind {
 +            normal.item.path == sym::no_core
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
 +/// ```rust
 +/// # struct S;
 +/// # trait Trait { fn f(); }
 +/// impl Trait for S {
 +///     fn f() {}
 +/// }
 +/// ```
 +pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
 +        matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates = cx
 +        .tcx
 +        .predicates_of(did)
 +        .predicates
 +        .iter()
 +        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
 +    traits::impossible_predicates(
 +        cx.tcx,
 +        traits::elaborate_predicates(cx.tcx, predicates)
 +            .map(|o| o.predicate)
 +            .collect::<Vec<_>>(),
 +    )
 +}
 +
 +/// Returns the `DefId` of the callee if the given expression is a function or method call.
 +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 +    match &expr.kind {
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(qpath),
 +                hir_id: path_hir_id,
 +                ..
 +            },
 +            ..,
 +        ) => {
 +            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
 +            // deref to fn pointers, dyn Fn, impl Fn - #8850
 +            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
 +                cx.typeck_results().qpath_res(qpath, *path_hir_id)
 +            {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +/// Returns `Option<String>` where String is a textual representation of the type encapsulated in
 +/// the slice iff the given expression is a slice of primitives (as defined in the
 +/// `is_recursively_primitive_type` function) and `None` otherwise.
 +pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
 +    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
 +    let expr_kind = expr_type.kind();
 +    let is_primitive = match expr_kind {
 +        rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
 +        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
 +            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
 +                is_recursively_primitive_type(*element_type)
 +            } else {
 +                unreachable!()
 +            }
 +        },
 +        _ => false,
 +    };
 +
 +    if is_primitive {
 +        // if we have wrappers like Array, Slice or Tuple, print these
 +        // and get the type enclosed in the slice ref
 +        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
 +            rustc_ty::Slice(..) => return Some("slice".into()),
 +            rustc_ty::Array(..) => return Some("array".into()),
 +            rustc_ty::Tuple(..) => return Some("tuple".into()),
 +            _ => {
 +                // is_recursively_primitive_type() should have taken care
 +                // of the rest and we can rely on the type that is found
 +                let refs_peeled = expr_type.peel_refs();
 +                return Some(refs_peeled.walk().last().unwrap().to_string());
 +            },
 +        }
 +    }
 +    None
 +}
 +
 +/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
 +/// `hash` must be comformed with `eq`
 +pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 +where
 +    Hash: Fn(&T) -> u64,
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    match exprs {
 +        [a, b] if eq(a, b) => return vec![(a, b)],
 +        _ if exprs.len() <= 2 => return vec![],
 +        _ => {},
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: UnhashMap<u64, Vec<&_>> =
 +        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 +
 +    for expr in exprs {
 +        match map.entry(hash(expr)) {
 +            Entry::Occupied(mut o) => {
 +                for o in o.get() {
 +                    if eq(o, expr) {
 +                        match_expr_list.push((o, expr));
 +                    }
 +                }
 +                o.get_mut().push(expr);
 +            },
 +            Entry::Vacant(v) => {
 +                v.insert(vec![expr]);
 +            },
 +        }
 +    }
 +
 +    match_expr_list
 +}
 +
 +/// Peels off all references on the pattern. Returns the underlying pattern and the number of
 +/// references removed.
 +pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
 +        if let PatKind::Ref(pat, _) = pat.kind {
 +            peel(pat, count + 1)
 +        } else {
 +            (pat, count)
 +        }
 +    }
 +    peel(pat, 0)
 +}
 +
 +/// Peels of expressions while the given closure returns `Some`.
 +pub fn peel_hir_expr_while<'tcx>(
 +    mut expr: &'tcx Expr<'tcx>,
 +    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
 +) -> &'tcx Expr<'tcx> {
 +    while let Some(e) = f(expr) {
 +        expr = e;
 +    }
 +    expr
 +}
 +
 +/// Peels off up to the given number of references on the expression. Returns the underlying
 +/// expression and the number of references removed.
 +pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
 +    let mut remaining = count;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
 +            remaining -= 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count - remaining)
 +}
 +
 +/// Peels off all references on the expression. Returns the underlying expression and the number of
 +/// references removed.
 +pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
 +    let mut count = 0;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
 +            count += 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count)
 +}
 +
 +/// Peels off all references on the type. Returns the underlying type and the number of references
 +/// removed.
 +pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) {
 +    let mut count = 0;
 +    loop {
 +        match &ty.kind {
 +            TyKind::Rptr(_, ref_ty) => {
 +                ty = ref_ty.ty;
 +                count += 1;
 +            },
 +            _ => break (ty, count),
 +        }
 +    }
 +}
 +
 +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 +pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 +    loop {
 +        match expr.kind {
 +            ExprKind::AddrOf(_, _, e) => expr = e,
 +            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +        if let Res::Def(_, def_id) = path.res {
 +            return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
 +        }
 +    }
 +    false
 +}
 +
 +static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = OnceLock::new();
 +
 +fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
 +    let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
 +    let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
 +    let value = map.entry(module);
 +    match value {
 +        Entry::Occupied(entry) => f(entry.get()),
 +        Entry::Vacant(entry) => {
 +            let mut names = Vec::new();
 +            for id in tcx.hir().module_items(module) {
 +                if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
 +                    && let item = tcx.hir().item(id)
 +                    && let ItemKind::Const(ty, _body) = item.kind {
 +                    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +                        // We could also check for the type name `test::TestDescAndFn`
 +                        if let Res::Def(DefKind::Struct, _) = path.res {
 +                            let has_test_marker = tcx
 +                                .hir()
 +                                .attrs(item.hir_id())
 +                                .iter()
 +                                .any(|a| a.has_name(sym::rustc_test_marker));
 +                            if has_test_marker {
 +                                names.push(item.ident.name);
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +            names.sort_unstable();
 +            f(entry.insert(names))
 +        },
 +    }
 +}
 +
 +/// Checks if the function containing the given `HirId` is a `#[test]` function
 +///
 +/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 +    with_test_item_names(tcx, tcx.parent_module(id), |names| {
 +        tcx.hir()
 +            .parent_iter(id)
 +            // Since you can nest functions we need to collect all until we leave
 +            // function scope
 +            .any(|(_id, node)| {
 +                if let Node::Item(item) = node {
 +                    if let ItemKind::Fn(_, _, _) = item.kind {
 +                        // Note that we have sorted the item names in the visitor,
 +                        // so the binary_search gets the same as `contains`, but faster.
 +                        return names.binary_search(&item.ident.name).is_ok();
 +                    }
 +                }
 +                false
 +            })
 +    })
 +}
 +
 +/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied
 +///
 +/// Note: Add `// compile-flags: --test` to UI tests with a `#[cfg(test)]` function
 +pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 +    fn is_cfg_test(attr: &Attribute) -> bool {
 +        if attr.has_name(sym::cfg)
 +            && let Some(items) = attr.meta_item_list()
 +            && let [item] = &*items
 +            && item.has_name(sym::test)
 +        {
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +    tcx.hir()
 +        .parent_iter(id)
 +        .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
 +        .any(is_cfg_test)
 +}
 +
 +/// Checks whether item either has `test` attribute applied, or
 +/// is a module with `test` in its name.
 +///
 +/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
 +    is_in_test_function(tcx, item.hir_id())
 +        || matches!(item.kind, ItemKind::Mod(..))
 +            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 +}
 +
 +/// Walks the HIR tree from the given expression, up to the node where the value produced by the
 +/// expression is consumed. Calls the function for every node encountered this way until it returns
 +/// `Some`.
 +///
 +/// This allows walking through `if`, `match`, `break`, block expressions to find where the value
 +/// produced by the expression is consumed.
 +pub fn walk_to_expr_usage<'tcx, T>(
 +    cx: &LateContext<'tcx>,
 +    e: &Expr<'tcx>,
 +    mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>,
 +) -> Option<T> {
 +    let map = cx.tcx.hir();
 +    let mut iter = map.parent_iter(e.hir_id);
 +    let mut child_id = e.hir_id;
 +
 +    while let Some((parent_id, parent)) = iter.next() {
 +        if let Some(x) = f(parent, child_id) {
 +            return Some(x);
 +        }
 +        let parent = match parent {
 +            Node::Expr(e) => e,
 +            Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
 +                child_id = parent_id;
 +                continue;
 +            },
 +            Node::Arm(a) if a.body.hir_id == child_id => {
 +                child_id = parent_id;
 +                continue;
 +            },
 +            _ => return None,
 +        };
 +        match parent.kind {
 +            ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
 +            ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
 +                child_id = id;
 +                iter = map.parent_iter(id);
 +            },
 +            ExprKind::Block(..) => child_id = parent_id,
 +            _ => return None,
 +        }
 +    }
 +    None
 +}
 +
 +/// 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 {
 +    let Ok(snippet) = sm.span_to_snippet(span) else { return false };
 +    return tokenize(&snippet).any(|token| {
 +        matches!(
 +            token.kind,
 +            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
 +        )
 +    });
 +}
 +
 +/// Return all the comments a given span contains
 +/// 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")
 +}
 +
 +macro_rules! op_utils {
 +    ($($name:ident $assign:ident)*) => {
 +        /// Binary operation traits like `LangItem::Add`
 +        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
 +
 +        /// Operator-Assign traits like `LangItem::AddAssign`
 +        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
 +
 +        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
 +        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
 +            match kind {
 +                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
 +                _ => None,
 +            }
 +        }
 +    };
 +}
 +
 +op_utils! {
 +    Add    AddAssign
 +    Sub    SubAssign
 +    Mul    MulAssign
 +    Div    DivAssign
 +    Rem    RemAssign
 +    BitXor BitXorAssign
 +    BitAnd BitAndAssign
 +    BitOr  BitOrAssign
 +    Shl    ShlAssign
 +    Shr    ShrAssign
 +}
index d13b34a66cca783ea01a70426ca6316af8684471,0000000000000000000000000000000000000000..77c5f1155423c4a7a4399694988e3b56442bae5a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1055 -1,0 +1,1061 @@@
 +#![allow(clippy::similar_names)] // `expr` and `expn`
 +
 +use crate::is_path_diagnostic_item;
 +use crate::source::snippet_opt;
 +use crate::visitors::{for_each_expr, Descend};
 +
 +use arrayvec::ArrayVec;
 +use itertools::{izip, Either, Itertools};
 +use rustc_ast::ast::LitKind;
 +use rustc_hir::intravisit::{walk_expr, Visitor};
 +use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
 +use rustc_lexer::unescape::unescape_literal;
 +use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 +use rustc_lint::LateContext;
 +use rustc_parse_format::{self as rpf, Alignment};
 +use rustc_span::def_id::DefId;
 +use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
 +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
 +use std::iter::{once, zip};
 +use std::ops::ControlFlow;
 +
 +const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
 +    sym::assert_eq_macro,
 +    sym::assert_macro,
 +    sym::assert_ne_macro,
 +    sym::debug_assert_eq_macro,
 +    sym::debug_assert_macro,
 +    sym::debug_assert_ne_macro,
 +    sym::eprint_macro,
 +    sym::eprintln_macro,
 +    sym::format_args_macro,
 +    sym::format_macro,
 +    sym::print_macro,
 +    sym::println_macro,
 +    sym::std_panic_macro,
 +    sym::write_macro,
 +    sym::writeln_macro,
 +];
 +
 +/// Returns true if a given Macro `DefId` is a format macro (e.g. `println!`)
 +pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
 +    if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
 +        FORMAT_MACRO_DIAG_ITEMS.contains(&name)
 +    } else {
 +        false
 +    }
 +}
 +
 +/// A macro call, like `vec![1, 2, 3]`.
 +///
 +/// Use `tcx.item_name(macro_call.def_id)` to get the macro name.
 +/// Even better is to check if it is a diagnostic item.
 +///
 +/// This structure is similar to `ExpnData` but it precludes desugaring expansions.
 +#[derive(Debug)]
 +pub struct MacroCall {
 +    /// Macro `DefId`
 +    pub def_id: DefId,
 +    /// Kind of macro
 +    pub kind: MacroKind,
 +    /// The expansion produced by the macro call
 +    pub expn: ExpnId,
 +    /// Span of the macro call site
 +    pub span: Span,
 +}
 +
 +impl MacroCall {
 +    pub fn is_local(&self) -> bool {
 +        span_is_local(self.span)
 +    }
 +}
 +
 +/// Returns an iterator of expansions that created the given span
 +pub fn expn_backtrace(mut span: Span) -> impl Iterator<Item = (ExpnId, ExpnData)> {
 +    std::iter::from_fn(move || {
 +        let ctxt = span.ctxt();
 +        if ctxt == SyntaxContext::root() {
 +            return None;
 +        }
 +        let expn = ctxt.outer_expn();
 +        let data = expn.expn_data();
 +        span = data.call_site;
 +        Some((expn, data))
 +    })
 +}
 +
 +/// Checks whether the span is from the root expansion or a locally defined macro
 +pub fn span_is_local(span: Span) -> bool {
 +    !span.from_expansion() || expn_is_local(span.ctxt().outer_expn())
 +}
 +
 +/// Checks whether the expansion is the root expansion or a locally defined macro
 +pub fn expn_is_local(expn: ExpnId) -> bool {
 +    if expn == ExpnId::root() {
 +        return true;
 +    }
 +    let data = expn.expn_data();
 +    let backtrace = expn_backtrace(data.call_site);
 +    std::iter::once((expn, data))
 +        .chain(backtrace)
 +        .find_map(|(_, data)| data.macro_def_id)
 +        .map_or(true, DefId::is_local)
 +}
 +
 +/// Returns an iterator of macro expansions that created the given span.
 +/// Note that desugaring expansions are skipped.
 +pub fn macro_backtrace(span: Span) -> impl Iterator<Item = MacroCall> {
 +    expn_backtrace(span).filter_map(|(expn, data)| match data {
 +        ExpnData {
 +            kind: ExpnKind::Macro(kind, _),
 +            macro_def_id: Some(def_id),
 +            call_site: span,
 +            ..
 +        } => Some(MacroCall {
 +            def_id,
 +            kind,
 +            expn,
 +            span,
 +        }),
 +        _ => None,
 +    })
 +}
 +
 +/// If the macro backtrace of `span` has a macro call at the root expansion
 +/// (i.e. not a nested macro call), returns `Some` with the `MacroCall`
 +pub fn root_macro_call(span: Span) -> Option<MacroCall> {
 +    macro_backtrace(span).last()
 +}
 +
 +/// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node"
 +/// produced by the macro call, as in [`first_node_in_macro`].
 +pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option<MacroCall> {
 +    if first_node_in_macro(cx, node) != Some(ExpnId::root()) {
 +        return None;
 +    }
 +    root_macro_call(node.span())
 +}
 +
 +/// Like [`macro_backtrace`], but only returns macro calls where `node` is the "first node" of the
 +/// macro call, as in [`first_node_in_macro`].
 +pub fn first_node_macro_backtrace(cx: &LateContext<'_>, node: &impl HirNode) -> impl Iterator<Item = MacroCall> {
 +    let span = node.span();
 +    first_node_in_macro(cx, node)
 +        .into_iter()
 +        .flat_map(move |expn| macro_backtrace(span).take_while(move |macro_call| macro_call.expn != expn))
 +}
 +
 +/// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the
 +/// macro call site (i.e. the parent of the macro expansion). This generally means that `node`
 +/// is the outermost node of an entire macro expansion, but there are some caveats noted below.
 +/// This is useful for finding macro calls while visiting the HIR without processing the macro call
 +/// at every node within its expansion.
 +///
 +/// If you already have immediate access to the parent node, it is simpler to
 +/// just check the context of that span directly (e.g. `parent.span.from_expansion()`).
 +///
 +/// If a macro call is in statement position, it expands to one or more statements.
 +/// In that case, each statement *and* their immediate descendants will all yield `Some`
 +/// with the `ExpnId` of the containing block.
 +///
 +/// A node may be the "first node" of multiple macro calls in a macro backtrace.
 +/// The expansion of the outermost macro call site is returned in such cases.
 +pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option<ExpnId> {
 +    // get the macro expansion or return `None` if not found
 +    // `macro_backtrace` importantly ignores desugaring expansions
 +    let expn = macro_backtrace(node.span()).next()?.expn;
 +
 +    // get the parent node, possibly skipping over a statement
 +    // if the parent is not found, it is sensible to return `Some(root)`
 +    let hir = cx.tcx.hir();
 +    let mut parent_iter = hir.parent_iter(node.hir_id());
 +    let (parent_id, _) = match parent_iter.next() {
 +        None => return Some(ExpnId::root()),
 +        Some((_, Node::Stmt(_))) => match parent_iter.next() {
 +            None => return Some(ExpnId::root()),
 +            Some(next) => next,
 +        },
 +        Some(next) => next,
 +    };
 +
 +    // get the macro expansion of the parent node
 +    let parent_span = hir.span(parent_id);
 +    let Some(parent_macro_call) = macro_backtrace(parent_span).next() else {
 +        // the parent node is not in a macro
 +        return Some(ExpnId::root());
 +    };
 +
 +    if parent_macro_call.expn.is_descendant_of(expn) {
 +        // `node` is input to a macro call
 +        return None;
 +    }
 +
 +    Some(parent_macro_call.expn)
 +}
 +
 +/* Specific Macro Utils */
 +
 +/// Is `def_id` of `std::panic`, `core::panic` or any inner implementation macros
 +pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
 +    matches!(
 +        name,
 +        sym::core_panic_macro
 +            | sym::std_panic_macro
 +            | sym::core_panic_2015_macro
 +            | sym::std_panic_2015_macro
 +            | sym::core_panic_2021_macro
 +    )
 +}
 +
++/// Is `def_id` of `assert!` or `debug_assert!`
++pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
++    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
++    matches!(name, sym::assert_macro | sym::debug_assert_macro)
++}
++
 +pub enum PanicExpn<'a> {
 +    /// No arguments - `panic!()`
 +    Empty,
 +    /// A string literal or any `&str` - `panic!("message")` or `panic!(message)`
 +    Str(&'a Expr<'a>),
 +    /// A single argument that implements `Display` - `panic!("{}", object)`
 +    Display(&'a Expr<'a>),
 +    /// Anything else - `panic!("error {}: {}", a, b)`
 +    Format(FormatArgsExpn<'a>),
 +}
 +
 +impl<'a> PanicExpn<'a> {
 +    pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Self> {
 +        if !macro_backtrace(expr.span).any(|macro_call| is_panic(cx, macro_call.def_id)) {
 +            return None;
 +        }
 +        let ExprKind::Call(callee, [arg]) = &expr.kind else { return None };
 +        let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None };
 +        let result = match path.segments.last().unwrap().ident.as_str() {
 +            "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
 +            "panic" | "panic_str" => Self::Str(arg),
 +            "panic_display" => {
 +                let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None };
 +                Self::Display(e)
 +            },
 +            "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?),
 +            _ => return None,
 +        };
 +        Some(result)
 +    }
 +}
 +
 +/// Finds the arguments of an `assert!` or `debug_assert!` macro call within the macro expansion
 +pub fn find_assert_args<'a>(
 +    cx: &LateContext<'_>,
 +    expr: &'a Expr<'a>,
 +    expn: ExpnId,
 +) -> Option<(&'a Expr<'a>, PanicExpn<'a>)> {
 +    find_assert_args_inner(cx, expr, expn).map(|([e], p)| (e, p))
 +}
 +
 +/// Finds the arguments of an `assert_eq!` or `debug_assert_eq!` macro call within the macro
 +/// expansion
 +pub fn find_assert_eq_args<'a>(
 +    cx: &LateContext<'_>,
 +    expr: &'a Expr<'a>,
 +    expn: ExpnId,
 +) -> Option<(&'a Expr<'a>, &'a Expr<'a>, PanicExpn<'a>)> {
 +    find_assert_args_inner(cx, expr, expn).map(|([a, b], p)| (a, b, p))
 +}
 +
 +fn find_assert_args_inner<'a, const N: usize>(
 +    cx: &LateContext<'_>,
 +    expr: &'a Expr<'a>,
 +    expn: ExpnId,
 +) -> Option<([&'a Expr<'a>; N], PanicExpn<'a>)> {
 +    let macro_id = expn.expn_data().macro_def_id?;
 +    let (expr, expn) = match cx.tcx.item_name(macro_id).as_str().strip_prefix("debug_") {
 +        None => (expr, expn),
 +        Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?,
 +    };
 +    let mut args = ArrayVec::new();
 +    let mut panic_expn = None;
 +    let _: Option<!> = for_each_expr(expr, |e| {
 +        if args.is_full() {
 +            if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() {
 +                panic_expn = PanicExpn::parse(cx, e);
 +            }
 +            ControlFlow::Continue(Descend::from(panic_expn.is_none()))
 +        } else if is_assert_arg(cx, e, expn) {
 +            args.push(e);
 +            ControlFlow::Continue(Descend::No)
 +        } else {
 +            ControlFlow::Continue(Descend::Yes)
 +        }
 +    });
 +    let args = args.into_inner().ok()?;
 +    // if no `panic!(..)` is found, use `PanicExpn::Empty`
 +    // to indicate that the default assertion message is used
 +    let panic_expn = panic_expn.unwrap_or(PanicExpn::Empty);
 +    Some((args, panic_expn))
 +}
 +
 +fn find_assert_within_debug_assert<'a>(
 +    cx: &LateContext<'_>,
 +    expr: &'a Expr<'a>,
 +    expn: ExpnId,
 +    assert_name: Symbol,
 +) -> Option<(&'a Expr<'a>, ExpnId)> {
 +    for_each_expr(expr, |e| {
 +        if !e.span.from_expansion() {
 +            return ControlFlow::Continue(Descend::No);
 +        }
 +        let e_expn = e.span.ctxt().outer_expn();
 +        if e_expn == expn {
 +            ControlFlow::Continue(Descend::Yes)
 +        } else if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) {
 +            ControlFlow::Break((e, e_expn))
 +        } else {
 +            ControlFlow::Continue(Descend::No)
 +        }
 +    })
 +}
 +
 +fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool {
 +    if !expr.span.from_expansion() {
 +        return true;
 +    }
 +    let result = macro_backtrace(expr.span).try_for_each(|macro_call| {
 +        if macro_call.expn == assert_expn {
 +            ControlFlow::Break(false)
 +        } else {
 +            match cx.tcx.item_name(macro_call.def_id) {
 +                // `cfg!(debug_assertions)` in `debug_assert!`
 +                sym::cfg => ControlFlow::CONTINUE,
 +                // assert!(other_macro!(..))
 +                _ => ControlFlow::Break(true),
 +            }
 +        }
 +    });
 +    match result {
 +        ControlFlow::Break(is_assert_arg) => is_assert_arg,
 +        ControlFlow::Continue(()) => true,
 +    }
 +}
 +
 +/// The format string doesn't exist in the HIR, so we reassemble it from source code
 +#[derive(Debug)]
 +pub struct FormatString {
 +    /// Span of the whole format string literal, including `[r#]"`.
 +    pub span: Span,
 +    /// Snippet of the whole format string literal, including `[r#]"`.
 +    pub snippet: String,
 +    /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side.
 +    pub style: Option<usize>,
 +    /// The unescaped value of the format string, e.g. `"val – {}"` for the literal
 +    /// `"val \u{2013} {}"`.
 +    pub unescaped: String,
 +    /// The format string split by format args like `{..}`.
 +    pub parts: Vec<Symbol>,
 +}
 +
 +impl FormatString {
 +    fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option<Self> {
 +        // format_args!(r"a {} b \", 1);
 +        //
 +        // expands to
 +        //
 +        // ::core::fmt::Arguments::new_v1(&["a ", " b \\"],
 +        //      &[::core::fmt::ArgumentV1::new_display(&1)]);
 +        //
 +        // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"`
 +        let span = pieces.span;
 +        let snippet = snippet_opt(cx, span)?;
 +
 +        let (inner, style) = match tokenize(&snippet).next()?.kind {
 +            TokenKind::Literal { kind, .. } => {
 +                let style = match kind {
 +                    LiteralKind::Str { .. } => None,
 +                    LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()),
 +                    _ => return None,
 +                };
 +
 +                let start = style.map_or(1, |n| 2 + n);
 +                let end = snippet.len() - style.map_or(1, |n| 1 + n);
 +
 +                (&snippet[start..end], style)
 +            },
 +            _ => return None,
 +        };
 +
 +        let mode = if style.is_some() {
 +            unescape::Mode::RawStr
 +        } else {
 +            unescape::Mode::Str
 +        };
 +
 +        let mut unescaped = String::with_capacity(inner.len());
 +        unescape_literal(inner, mode, &mut |_, ch| match ch {
 +            Ok(ch) => unescaped.push(ch),
 +            Err(e) if !e.is_fatal() => (),
 +            Err(e) => panic!("{e:?}"),
 +        });
 +
 +        let mut parts = Vec::new();
 +        let _: Option<!> = for_each_expr(pieces, |expr| {
 +            if let ExprKind::Lit(lit) = &expr.kind
 +                && let LitKind::Str(symbol, _) = lit.node
 +            {
 +                parts.push(symbol);
 +            }
 +            ControlFlow::Continue(())
 +        });
 +
 +        Some(Self {
 +            span,
 +            snippet,
 +            style,
 +            unescaped,
 +            parts,
 +        })
 +    }
 +}
 +
 +struct FormatArgsValues<'tcx> {
 +    /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
 +    /// `format!("{x} {} {}", 1, z + 2)`.
 +    value_args: Vec<&'tcx Expr<'tcx>>,
 +    /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in
 +    /// `value_args`
 +    pos_to_value_index: Vec<usize>,
 +    /// Used to check if a value is declared inline & to resolve `InnerSpan`s.
 +    format_string_span: SpanData,
 +}
 +
 +impl<'tcx> FormatArgsValues<'tcx> {
 +    fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
 +        let mut pos_to_value_index = Vec::new();
 +        let mut value_args = Vec::new();
 +        let _: Option<!> = for_each_expr(args, |expr| {
 +            if expr.span.ctxt() == args.span.ctxt() {
 +                // ArgumentV1::new_<format_trait>(<val>)
 +                // ArgumentV1::from_usize(<val>)
 +                if let ExprKind::Call(callee, [val]) = expr.kind
 +                    && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
 +                    && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
 +                    && path.segments.last().unwrap().ident.name == sym::ArgumentV1
 +                {
 +                    let val_idx = if val.span.ctxt() == expr.span.ctxt()
 +                        && let ExprKind::Field(_, field) = val.kind
 +                        && let Ok(idx) = field.name.as_str().parse()
 +                    {
 +                        // tuple index
 +                        idx
 +                    } else {
 +                        // assume the value expression is passed directly
 +                        pos_to_value_index.len()
 +                    };
 +
 +                    pos_to_value_index.push(val_idx);
 +                }
 +                ControlFlow::Continue(Descend::Yes)
 +            } else {
 +                // assume that any expr with a differing span is a value
 +                value_args.push(expr);
 +                ControlFlow::Continue(Descend::No)
 +            }
 +        });
 +
 +        Self {
 +            value_args,
 +            pos_to_value_index,
 +            format_string_span,
 +        }
 +    }
 +}
 +
 +/// The positions of a format argument's value, precision and width
 +///
 +/// A position is an index into the second argument of `Arguments::new_v1[_formatted]`
 +#[derive(Debug, Default, Copy, Clone)]
 +struct ParamPosition {
 +    /// The position stored in `rt::v1::Argument::position`.
 +    value: usize,
 +    /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`.
 +    width: Option<usize>,
 +    /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`.
 +    precision: Option<usize>,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ParamPosition {
 +    fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
 +        fn parse_count(expr: &Expr<'_>) -> Option<usize> {
 +            // ::core::fmt::rt::v1::Count::Param(1usize),
 +            if let ExprKind::Call(ctor, [val]) = expr.kind
 +                && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
 +                && path.segments.last()?.ident.name == sym::Param
 +                && let ExprKind::Lit(lit) = &val.kind
 +                && let LitKind::Int(pos, _) = lit.node
 +            {
 +                Some(pos as usize)
 +            } else {
 +                None
 +            }
 +        }
 +
 +        match field.ident.name {
 +            sym::position => {
 +                if let ExprKind::Lit(lit) = &field.expr.kind
 +                    && let LitKind::Int(pos, _) = lit.node
 +                {
 +                    self.value = pos as usize;
 +                }
 +            },
 +            sym::precision => {
 +                self.precision = parse_count(field.expr);
 +            },
 +            sym::width => {
 +                self.width = parse_count(field.expr);
 +            },
 +            _ => walk_expr(self, field.expr),
 +        }
 +    }
 +}
 +
 +/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
 +fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
 +    if let ExprKind::AddrOf(.., array) = fmt_arg.kind
 +        && let ExprKind::Array(specs) = array.kind
 +    {
 +        Some(specs.iter().map(|spec| {
 +            let mut position = ParamPosition::default();
 +            position.visit_expr(spec);
 +            position
 +        }))
 +    } else {
 +        None
 +    }
 +}
 +
 +/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan`
 +fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span {
 +    Span::new(
 +        base.lo + BytePos::from_usize(inner.start),
 +        base.lo + BytePos::from_usize(inner.end),
 +        base.ctxt,
 +        base.parent,
 +    )
 +}
 +
 +/// How a format parameter is used in the format string
 +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 +pub enum FormatParamKind {
 +    /// An implicit parameter , such as `{}` or `{:?}`.
 +    Implicit,
 +    /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}`
 +    Numbered,
 +    /// A parameter with an asterisk precision. e.g. `{:.*}`.
 +    Starred,
 +    /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`.
 +    Named(Symbol),
 +    /// An implicit named parameter, such as the `y` in `format!("{y}")`.
 +    NamedInline(Symbol),
 +}
 +
 +/// Where a format parameter is being used in the format string
 +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 +pub enum FormatParamUsage {
 +    /// Appears as an argument, e.g. `format!("{}", foo)`
 +    Argument,
 +    /// Appears as a width, e.g. `format!("{:width$}", foo, width = 1)`
 +    Width,
 +    /// Appears as a precision, e.g. `format!("{:.precision$}", foo, precision = 1)`
 +    Precision,
 +}
 +
 +/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g.
 +///
 +/// ```
 +/// let precision = 2;
 +/// format!("{:.precision$}", 0.1234);
 +/// ```
 +///
 +/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234`
 +/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2`
 +#[derive(Debug, Copy, Clone)]
 +pub struct FormatParam<'tcx> {
 +    /// The expression this parameter refers to.
 +    pub value: &'tcx Expr<'tcx>,
 +    /// How this parameter refers to its `value`.
 +    pub kind: FormatParamKind,
 +    /// Where this format param is being used - argument/width/precision
 +    pub usage: FormatParamUsage,
 +    /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters.
 +    ///
 +    /// ```text
 +    /// format!("{}, {  }, {0}, {name}", ...);
 +    ///          ^    ~~    ~    ~~~~
 +    /// ```
 +    pub span: Span,
 +}
 +
 +impl<'tcx> FormatParam<'tcx> {
 +    fn new(
 +        mut kind: FormatParamKind,
 +        usage: FormatParamUsage,
 +        position: usize,
 +        inner: rpf::InnerSpan,
 +        values: &FormatArgsValues<'tcx>,
 +    ) -> Option<Self> {
 +        let value_index = *values.pos_to_value_index.get(position)?;
 +        let value = *values.value_args.get(value_index)?;
 +        let span = span_from_inner(values.format_string_span, inner);
 +
 +        // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points
 +        // into the format string
 +        if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) {
 +            kind = FormatParamKind::NamedInline(name);
 +        }
 +
 +        Some(Self {
 +            value,
 +            kind,
 +            usage,
 +            span,
 +        })
 +    }
 +}
 +
 +/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and
 +/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
 +#[derive(Debug, Copy, Clone)]
 +pub enum Count<'tcx> {
 +    /// Specified with a literal number, stores the value.
 +    Is(usize, Span),
 +    /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be
 +    /// `FormatParamKind::Numbered`.
 +    Param(FormatParam<'tcx>),
 +    /// Not specified.
 +    Implied(Option<Span>),
 +}
 +
 +impl<'tcx> Count<'tcx> {
 +    fn new(
 +        usage: FormatParamUsage,
 +        count: rpf::Count<'_>,
 +        position: Option<usize>,
 +        inner: Option<rpf::InnerSpan>,
 +        values: &FormatArgsValues<'tcx>,
 +    ) -> Option<Self> {
 +        let span = inner.map(|inner| span_from_inner(values.format_string_span, inner));
 +
 +        Some(match count {
 +            rpf::Count::CountIs(val) => Self::Is(val, span?),
 +            rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new(
 +                FormatParamKind::Named(Symbol::intern(name)),
 +                usage,
 +                position?,
 +                inner?,
 +                values,
 +            )?),
 +            rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new(
 +                FormatParamKind::Numbered,
 +                usage,
 +                position?,
 +                inner?,
 +                values,
 +            )?),
 +            rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new(
 +                FormatParamKind::Starred,
 +                usage,
 +                position?,
 +                inner?,
 +                values,
 +            )?),
 +            rpf::Count::CountImplied => Self::Implied(span),
 +        })
 +    }
 +
 +    pub fn is_implied(self) -> bool {
 +        matches!(self, Count::Implied(_))
 +    }
 +
 +    pub fn param(self) -> Option<FormatParam<'tcx>> {
 +        match self {
 +            Count::Param(param) => Some(param),
 +            _ => None,
 +        }
 +    }
 +
 +    pub fn span(self) -> Option<Span> {
 +        match self {
 +            Count::Is(_, span) => Some(span),
 +            Count::Param(param) => Some(param.span),
 +            Count::Implied(span) => span,
 +        }
 +    }
 +}
 +
 +/// Specification for the formatting of an argument in the format string. See
 +/// <https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters> for the precise meanings.
 +#[derive(Debug)]
 +pub struct FormatSpec<'tcx> {
 +    /// Optionally specified character to fill alignment with.
 +    pub fill: Option<char>,
 +    /// Optionally specified alignment.
 +    pub align: Alignment,
 +    /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
 +    pub flags: u32,
 +    /// Represents either the maximum width or the integer precision.
 +    pub precision: Count<'tcx>,
 +    /// The minimum width, will be padded according to `width`/`align`
 +    pub width: Count<'tcx>,
 +    /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for
 +    /// `{:?}`.
 +    pub r#trait: Symbol,
 +    pub trait_span: Option<Span>,
 +}
 +
 +impl<'tcx> FormatSpec<'tcx> {
 +    fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option<Self> {
 +        Some(Self {
 +            fill: spec.fill,
 +            align: spec.align,
 +            flags: spec.flags,
 +            precision: Count::new(
 +                FormatParamUsage::Precision,
 +                spec.precision,
 +                positions.precision,
 +                spec.precision_span,
 +                values,
 +            )?,
 +            width: Count::new(
 +                FormatParamUsage::Width,
 +                spec.width,
 +                positions.width,
 +                spec.width_span,
 +                values,
 +            )?,
 +            r#trait: match spec.ty {
 +                "" => sym::Display,
 +                "?" => sym::Debug,
 +                "o" => sym!(Octal),
 +                "x" => sym!(LowerHex),
 +                "X" => sym!(UpperHex),
 +                "p" => sym::Pointer,
 +                "b" => sym!(Binary),
 +                "e" => sym!(LowerExp),
 +                "E" => sym!(UpperExp),
 +                _ => return None,
 +            },
 +            trait_span: spec
 +                .ty_span
 +                .map(|span| span_from_inner(values.format_string_span, span)),
 +        })
 +    }
 +
 +    /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`,
 +    /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}`
 +    pub fn is_default(&self) -> bool {
 +        self.r#trait == sym::Display && self.is_default_for_trait()
 +    }
 +
 +    /// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
 +    /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
 +    pub fn is_default_for_trait(&self) -> bool {
 +        self.width.is_implied()
 +            && self.precision.is_implied()
 +            && self.align == Alignment::AlignUnknown
 +            && self.flags == 0
 +    }
 +}
 +
 +/// A format argument, such as `{}`, `{foo:?}`.
 +#[derive(Debug)]
 +pub struct FormatArg<'tcx> {
 +    /// The parameter the argument refers to.
 +    pub param: FormatParam<'tcx>,
 +    /// How to format `param`.
 +    pub format: FormatSpec<'tcx>,
 +    /// span of the whole argument, `{..}`.
 +    pub span: Span,
 +}
 +
 +impl<'tcx> FormatArg<'tcx> {
 +    /// Span of the `:` and format specifiers
 +    ///
 +    /// ```ignore
 +    /// format!("{:.}"), format!("{foo:.}")
 +    ///           ^^                  ^^
 +    /// ```
 +    pub fn format_span(&self) -> Span {
 +        let base = self.span.data();
 +
 +        // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing
 +        // brace `{...|}`
 +        Span::new(self.param.span.hi(), base.hi - BytePos(1), base.ctxt, base.parent)
 +    }
 +}
 +
 +/// A parsed `format_args!` expansion.
 +#[derive(Debug)]
 +pub struct FormatArgsExpn<'tcx> {
 +    /// The format string literal.
 +    pub format_string: FormatString,
 +    /// The format arguments, such as `{:?}`.
 +    pub args: Vec<FormatArg<'tcx>>,
 +    /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will
 +    /// include this added newline.
 +    pub newline: bool,
 +    /// Spans of the commas between the format string and explicit values, excluding any trailing
 +    /// comma
 +    ///
 +    /// ```ignore
 +    /// format!("..", 1, 2, 3,)
 +    /// //          ^  ^  ^
 +    /// ```
 +    comma_spans: Vec<Span>,
 +    /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for
 +    /// `format!("{x} {} {y}", 1, z + 2)`.
 +    explicit_values: Vec<&'tcx Expr<'tcx>>,
 +}
 +
 +impl<'tcx> FormatArgsExpn<'tcx> {
 +    /// Gets the spans of the commas inbetween the format string and explicit args, not including
 +    /// any trailing comma
 +    ///
 +    /// ```ignore
 +    /// format!("{} {}", a, b)
 +    /// //             ^  ^
 +    /// ```
 +    ///
 +    /// Ensures that the format string and values aren't coming from a proc macro that sets the
 +    /// output span to that of its input
 +    fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option<Vec<Span>> {
 +        // `format!("{} {} {c}", "one", "two", c = "three")`
 +        //                       ^^^^^  ^^^^^      ^^^^^^^
 +        let value_spans = explicit_values
 +            .iter()
 +            .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt()));
 +
 +        // `format!("{} {} {c}", "one", "two", c = "three")`
 +        //                     ^^     ^^     ^^^^^^
 +        let between_spans = once(fmt_span)
 +            .chain(value_spans)
 +            .tuple_windows()
 +            .map(|(start, end)| start.between(end));
 +
 +        let mut comma_spans = Vec::new();
 +        for between_span in between_spans {
 +            let mut offset = 0;
 +            let mut seen_comma = false;
 +
 +            for token in tokenize(&snippet_opt(cx, between_span)?) {
 +                match token.kind {
 +                    TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {},
 +                    TokenKind::Comma if !seen_comma => {
 +                        seen_comma = true;
 +
 +                        let base = between_span.data();
 +                        comma_spans.push(Span::new(
 +                            base.lo + BytePos(offset),
 +                            base.lo + BytePos(offset + 1),
 +                            base.ctxt,
 +                            base.parent,
 +                        ));
 +                    },
 +                    // named arguments, `start_val, name = end_val`
 +                    //                            ^^^^^^^^^ between_span
 +                    TokenKind::Ident | TokenKind::Eq if seen_comma => {},
 +                    // An unexpected token usually indicates the format string or a value came from a proc macro output
 +                    // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that
 +                    // emits a string literal with the span set to that of `"input"`
 +                    _ => return None,
 +                }
 +                offset += token.len;
 +            }
 +
 +            if !seen_comma {
 +                return None;
 +            }
 +        }
 +
 +        Some(comma_spans)
 +    }
 +
 +    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
 +        let macro_name = macro_backtrace(expr.span)
 +            .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
 +            .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
 +        let newline = macro_name == sym::format_args_nl;
 +
 +        // ::core::fmt::Arguments::new_v1(pieces, args)
 +        // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
 +        if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
 +            && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
 +            && is_path_diagnostic_item(cx, ty, sym::Arguments)
 +            && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
 +        {
 +            let format_string = FormatString::new(cx, pieces)?;
 +
 +            let mut parser = rpf::Parser::new(
 +                &format_string.unescaped,
 +                format_string.style,
 +                Some(format_string.snippet.clone()),
 +                // `format_string.unescaped` does not contain the appended newline
 +                false,
 +                rpf::ParseMode::Format,
 +            );
 +
 +            let parsed_args = parser
 +                .by_ref()
 +                .filter_map(|piece| match piece {
 +                    rpf::Piece::NextArgument(a) => Some(a),
 +                    rpf::Piece::String(_) => None,
 +                })
 +                .collect_vec();
 +            if !parser.errors.is_empty() {
 +                return None;
 +            }
 +
 +            let positions = if let Some(fmt_arg) = rest.first() {
 +                // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
 +                // them.
 +
 +                Either::Left(parse_rt_fmt(fmt_arg)?)
 +            } else {
 +                // If no format specs are given, the positions are in the given order and there are
 +                // no `precision`/`width`s to consider.
 +
 +                Either::Right((0..).map(|n| ParamPosition {
 +                    value: n,
 +                    width: None,
 +                    precision: None,
 +                }))
 +            };
 +
 +            let values = FormatArgsValues::new(args, format_string.span.data());
 +
 +            let args = izip!(positions, parsed_args, parser.arg_places)
 +                .map(|(position, parsed_arg, arg_span)| {
 +                    Some(FormatArg {
 +                        param: FormatParam::new(
 +                            match parsed_arg.position {
 +                                rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit,
 +                                rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered,
 +                                // NamedInline is handled by `FormatParam::new()`
 +                                rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)),
 +                            },
 +                            FormatParamUsage::Argument,
 +                            position.value,
 +                            parsed_arg.position_span,
 +                            &values,
 +                        )?,
 +                        format: FormatSpec::new(parsed_arg.format, position, &values)?,
 +                        span: span_from_inner(values.format_string_span, arg_span),
 +                    })
 +                })
 +                .collect::<Option<Vec<_>>>()?;
 +
 +            let mut explicit_values = values.value_args;
 +            // remove values generated for implicitly captured vars
 +            let len = explicit_values
 +                .iter()
 +                .take_while(|val| !format_string.span.contains(val.span))
 +                .count();
 +            explicit_values.truncate(len);
 +
 +            let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?;
 +
 +            Some(Self {
 +                format_string,
 +                args,
 +                newline,
 +                comma_spans,
 +                explicit_values,
 +            })
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
 +        for_each_expr(expr, |e| {
 +            let e_ctxt = e.span.ctxt();
 +            if e_ctxt == expr.span.ctxt() {
 +                ControlFlow::Continue(Descend::Yes)
 +            } else if e_ctxt.outer_expn().is_descendant_of(expn_id) {
 +                if let Some(args) = FormatArgsExpn::parse(cx, e) {
 +                    ControlFlow::Break(args)
 +                } else {
 +                    ControlFlow::Continue(Descend::No)
 +                }
 +            } else {
 +                ControlFlow::Continue(Descend::No)
 +            }
 +        })
 +    }
 +
 +    /// Source callsite span of all inputs
 +    pub fn inputs_span(&self) -> Span {
 +        match *self.explicit_values {
 +            [] => self.format_string.span,
 +            [.., last] => self
 +                .format_string
 +                .span
 +                .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())),
 +        }
 +    }
 +
 +    /// Get the span of a value expanded to the previous comma, e.g. for the value `10`
 +    ///
 +    /// ```ignore
 +    /// format("{}.{}", 10, 11)
 +    /// //            ^^^^
 +    /// ```
 +    pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option<Span> {
 +        for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) {
 +            if value.hir_id == value_id {
 +                return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt())));
 +            }
 +        }
 +
 +        None
 +    }
 +
 +    /// Iterator of all format params, both values and those referenced by `width`/`precision`s.
 +    pub fn params(&'tcx self) -> impl Iterator<Item = FormatParam<'tcx>> {
 +        self.args
 +            .iter()
 +            .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()])
 +            .flatten()
 +    }
 +}
 +
 +/// A node with a `HirId` and a `Span`
 +pub trait HirNode {
 +    fn hir_id(&self) -> HirId;
 +    fn span(&self) -> Span;
 +}
 +
 +macro_rules! impl_hir_node {
 +    ($($t:ident),*) => {
 +        $(impl HirNode for hir::$t<'_> {
 +            fn hir_id(&self) -> HirId {
 +                self.hir_id
 +            }
 +            fn span(&self) -> Span {
 +                self.span
 +            }
 +        })*
 +    };
 +}
 +
 +impl_hir_node!(Expr, Pat);
 +
 +impl HirNode for hir::Item<'_> {
 +    fn hir_id(&self) -> HirId {
 +        self.hir_id()
 +    }
 +
 +    fn span(&self) -> Span {
 +        self.span
 +    }
 +}
index 12a512f78a699eb30c92ac178b17663db424d090,0000000000000000000000000000000000000000..ba5bc9c3135daa8ca34a9eddf552dafb332af796
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,143 @@@
-     1,58,0 { FORMAT_ARGS_CAPTURE }
 +use std::sync::OnceLock;
 +
 +use rustc_ast::Attribute;
 +use rustc_semver::RustcVersion;
 +use rustc_session::Session;
 +use rustc_span::Span;
 +
 +use crate::attrs::get_unique_attr;
 +
 +macro_rules! msrv_aliases {
 +    ($($major:literal,$minor:literal,$patch:literal {
 +        $($name:ident),* $(,)?
 +    })*) => {
 +        $($(
 +        pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch);
 +        )*)*
 +    };
 +}
 +
 +// names may refer to stabilized feature flags or library items
 +msrv_aliases! {
 +    1,65,0 { LET_ELSE }
 +    1,62,0 { BOOL_THEN_SOME }
++    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
 +    1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
 +    1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
 +    1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
 +    1,50,0 { BOOL_THEN, CLAMP }
 +    1,47,0 { TAU, IS_ASCII_DIGIT_CONST }
 +    1,46,0 { CONST_IF_MATCH }
 +    1,45,0 { STR_STRIP_PREFIX }
 +    1,43,0 { LOG2_10, LOG10_2 }
 +    1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
 +    1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
 +    1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
 +    1,38,0 { POINTER_CAST, REM_EUCLID }
 +    1,37,0 { TYPE_ALIAS_ENUM_VARIANTS }
 +    1,36,0 { ITERATOR_COPIED }
 +    1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
 +    1,34,0 { TRY_FROM }
 +    1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
 +    1,28,0 { FROM_BOOL }
 +    1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
 +    1,24,0 { IS_ASCII_DIGIT }
 +    1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
 +    1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
 +    1,16,0 { STR_REPEAT }
 +    1,55,0 { SEEK_REWIND }
 +}
 +
 +fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
 +    if let Ok(version) = RustcVersion::parse(msrv) {
 +        return Some(version);
 +    } else if let Some(sess) = sess {
 +        if let Some(span) = span {
 +            sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
 +        }
 +    }
 +    None
 +}
 +
 +/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
 +#[derive(Debug, Clone, Default)]
 +pub struct Msrv {
 +    stack: Vec<RustcVersion>,
 +}
 +
 +impl Msrv {
 +    fn new(initial: Option<RustcVersion>) -> Self {
 +        Self {
 +            stack: Vec::from_iter(initial),
 +        }
 +    }
 +
 +    fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
 +        let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
 +            .ok()
 +            .and_then(|v| parse_msrv(&v, None, None));
 +        let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
 +            parse_msrv(s, None, None).or_else(|| {
 +                sess.err(format!(
 +                    "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
 +                ));
 +                None
 +            })
 +        });
 +
 +        // if both files have an msrv, let's compare them and emit a warning if they differ
 +        if let Some(cargo_msrv) = cargo_msrv
 +            && let Some(clippy_msrv) = clippy_msrv
 +            && clippy_msrv != cargo_msrv
 +        {
 +            sess.warn(format!(
 +                "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
 +            ));
 +        }
 +
 +        Self::new(clippy_msrv.or(cargo_msrv))
 +    }
 +
 +    /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
 +    /// field in `Cargo.toml`
 +    ///
 +    /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
 +    /// `register_{late,early}_pass` callbacks
 +    pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
 +        static PARSED: OnceLock<Msrv> = OnceLock::new();
 +
 +        PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
 +    }
 +
 +    pub fn current(&self) -> Option<RustcVersion> {
 +        self.stack.last().copied()
 +    }
 +
 +    pub fn meets(&self, required: RustcVersion) -> bool {
 +        self.current().map_or(true, |version| version.meets(required))
 +    }
 +
 +    fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
 +        if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
 +            if let Some(msrv) = msrv_attr.value_str() {
 +                return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
 +            }
 +
 +            sess.span_err(msrv_attr.span, "bad clippy attribute");
 +        }
 +
 +        None
 +    }
 +
 +    pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
 +        if let Some(version) = Self::parse_attr(sess, attrs) {
 +            self.stack.push(version);
 +        }
 +    }
 +
 +    pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
 +        if Self::parse_attr(sess, attrs).is_some() {
 +            self.stack.pop();
 +        }
 +    }
 +}
index 6417f0f3c71348bb6761918cb08c7c373e7b9bc6,0000000000000000000000000000000000000000..9ca50105ae57d0e93c96f7b48d1030bb10011c85
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,158 @@@
- pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
 +//! This module contains paths to types and functions Clippy needs to know
 +//! about.
 +//!
 +//! Whenever possible, please consider diagnostic items over hardcoded paths.
 +//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 +
 +#[cfg(feature = "internal")]
 +pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
 +#[cfg(feature = "internal")]
 +pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
 +    ["rustc_lint_defs", "Applicability", "Unspecified"],
 +    ["rustc_lint_defs", "Applicability", "HasPlaceholders"],
 +    ["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
 +    ["rustc_lint_defs", "Applicability", "MachineApplicable"],
 +];
 +#[cfg(feature = "internal")]
 +pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
 +pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
 +pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
 +pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 +pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
 +pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 +pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 +pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 +pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
 +pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
 +pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
 +pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
 +#[cfg(feature = "internal")]
 +pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
 +#[cfg(feature = "internal")]
 +pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
 +pub const EXIT: [&str; 3] = ["std", "process", "exit"];
 +pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
 +pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
 +pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 +pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
 +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
 +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
 +pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
 +pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
 +pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
 +#[cfg(feature = "internal")]
 +pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 +#[cfg(feature = "internal")]
 +pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 +pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 +pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
 +pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
 +pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 +#[cfg(feature = "internal")]
 +pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
 +#[cfg(feature = "internal")]
 +pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
 +#[cfg(feature = "internal")]
 +pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
 +#[cfg(feature = "internal")]
 +pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
 +pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
 +#[cfg(feature = "internal")]
 +pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
 +pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
 +pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
 +pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
 +pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
 +pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
 +pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
 +pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 +pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 +pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
 +pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
 +#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
 +pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
 +pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
 +pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 +pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 +pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"];
 +pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"];
 +pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"];
 +pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"];
 +pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"];
 +pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"];
 +pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
 +pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
 +pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"];
 +pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"];
 +pub const PTR_WRITE: [&str; 3] = ["core", "ptr", "write"];
 +pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
 +pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"];
 +pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"];
 +pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 +pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 +pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 +pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 +pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
 +pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
 +pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
 +pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
 +pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
 +pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
 +pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
 +pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 +pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 +pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
 +pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
 +pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"];
 +pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 +pub const SLICE_INTO: [&str; 4] = ["core", "slice", "<impl [T]>", "iter"];
 +pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 +pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 +pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 +pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"];
 +pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
 +pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
 +pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
 +pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
 +pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
 +pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
 +pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
 +pub const STR_BYTES: [&str; 4] = ["core", "str", "<impl str>", "bytes"];
 +pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
 +pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
 +pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
 +pub const STR_FROM_UTF8_UNCHECKED: [&str; 4] = ["core", "str", "converts", "from_utf8_unchecked"];
 +pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
 +pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
 +#[cfg(feature = "internal")]
 +pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 +#[cfg(feature = "internal")]
 +pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 +pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 +pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
 +#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
 +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 +pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
 +pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 +pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
 +pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 +pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
 +pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 +pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 +pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 +pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
 +pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
 +pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
index 8bf542ada04dd80ace50f751c29337d8ecdd71d4,0000000000000000000000000000000000000000..e5d7da682813c16d4883f2985d0963c03eb03a7c
mode 100644,000000..100644
--- /dev/null
@@@ -1,397 -1,0 +1,394 @@@
-         TerminatorKind::SwitchInt {
-             discr,
-             targets: _,
-         } => check_operand(tcx, discr, span, body),
 +// This code used to be a part of `rustc` but moved to Clippy as a result of
 +// https://github.com/rust-lang/rust/issues/76618. Because of that, it contains unused code and some
 +// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
 +// differ from the time of `rustc` even if the name stays the same.
 +
 +use crate::msrvs::Msrv;
 +use rustc_hir as hir;
 +use rustc_hir::def_id::DefId;
 +use rustc_middle::mir::{
 +    Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
 +    Terminator, TerminatorKind,
 +};
 +use rustc_middle::ty::subst::GenericArgKind;
 +use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
 +use rustc_semver::RustcVersion;
 +use rustc_span::symbol::sym;
 +use rustc_span::Span;
 +use std::borrow::Cow;
 +
 +type McfResult = Result<(), (Span, Cow<'static, str>)>;
 +
 +pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
 +    let def_id = body.source.def_id();
 +    let mut current = def_id;
 +    loop {
 +        let predicates = tcx.predicates_of(current);
 +        for (predicate, _) in predicates.predicates {
 +            match predicate.kind().skip_binder() {
 +                ty::PredicateKind::Clause(
 +                    ty::Clause::RegionOutlives(_)
 +                    | ty::Clause::TypeOutlives(_)
 +                    | ty::Clause::Projection(_)
 +                    | ty::Clause::Trait(..),
 +                )
 +                | ty::PredicateKind::WellFormed(_)
 +                | ty::PredicateKind::ConstEvaluatable(..)
 +                | ty::PredicateKind::ConstEquate(..)
 +                | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
 +                ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
 +                ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
 +                ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
 +                ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
 +                ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"),
 +            }
 +        }
 +        match predicates.parent {
 +            Some(parent) => current = parent,
 +            None => break,
 +        }
 +    }
 +
 +    for local in &body.local_decls {
 +        check_ty(tcx, local.ty, local.source_info.span)?;
 +    }
 +    // impl trait is gone in MIR, so check the return type manually
 +    check_ty(
 +        tcx,
 +        tcx.fn_sig(def_id).output().skip_binder(),
 +        body.local_decls.iter().next().unwrap().source_info.span,
 +    )?;
 +
 +    for bb in body.basic_blocks.iter() {
 +        check_terminator(tcx, body, bb.terminator(), msrv)?;
 +        for stmt in &bb.statements {
 +            check_statement(tcx, body, def_id, stmt)?;
 +        }
 +    }
 +    Ok(())
 +}
 +
 +fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
 +    for arg in ty.walk() {
 +        let ty = match arg.unpack() {
 +            GenericArgKind::Type(ty) => ty,
 +
 +            // No constraints on lifetimes or constants, except potentially
 +            // constants' types, but `walk` will get to them as well.
 +            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue,
 +        };
 +
 +        match ty.kind() {
 +            ty::Ref(_, _, hir::Mutability::Mut) => {
 +                return Err((span, "mutable references in const fn are unstable".into()));
 +            },
 +            ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
 +            ty::FnPtr(..) => {
 +                return Err((span, "function pointers in const fn are unstable".into()));
 +            },
 +            ty::Dynamic(preds, _, _) => {
 +                for pred in preds.iter() {
 +                    match pred.skip_binder() {
 +                        ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
 +                            return Err((
 +                                span,
 +                                "trait bounds other than `Sized` \
 +                                 on const fn parameters are unstable"
 +                                    .into(),
 +                            ));
 +                        },
 +                        ty::ExistentialPredicate::Trait(trait_ref) => {
 +                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
 +                                return Err((
 +                                    span,
 +                                    "trait bounds other than `Sized` \
 +                                     on const fn parameters are unstable"
 +                                        .into(),
 +                                ));
 +                            }
 +                        },
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +    Ok(())
 +}
 +
 +fn check_rvalue<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    body: &Body<'tcx>,
 +    def_id: DefId,
 +    rvalue: &Rvalue<'tcx>,
 +    span: Span,
 +) -> McfResult {
 +    match rvalue {
 +        Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
 +        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
 +            check_place(tcx, *place, span, body)
 +        },
 +        Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
 +        Rvalue::Repeat(operand, _)
 +        | Rvalue::Use(operand)
 +        | Rvalue::Cast(
 +            CastKind::PointerFromExposedAddress
 +            | CastKind::IntToInt
 +            | CastKind::FloatToInt
 +            | CastKind::IntToFloat
 +            | CastKind::FloatToFloat
 +            | CastKind::FnPtrToPtr
 +            | CastKind::PtrToPtr
 +            | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
 +            operand,
 +            _,
 +        ) => check_operand(tcx, operand, span, body),
 +        Rvalue::Cast(
 +            CastKind::Pointer(
 +                PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
 +            ),
 +            _,
 +            _,
 +        ) => Err((span, "function pointer casts are not allowed in const fn".into())),
 +        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => {
 +            let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
 +                deref_ty.ty
 +            } else {
 +                // We cannot allow this for now.
 +                return Err((span, "unsizing casts are only allowed for references right now".into()));
 +            };
 +            let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
 +            if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
 +                check_operand(tcx, op, span, body)?;
 +                // Casting/coercing things to slices is fine.
 +                Ok(())
 +            } else {
 +                // We just can't allow trait objects until we have figured out trait method calls.
 +                Err((span, "unsizing casts are not allowed in const fn".into()))
 +            }
 +        },
 +        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
 +            Err((span, "casting pointers to ints is unstable in const fn".into()))
 +        },
 +        Rvalue::Cast(CastKind::DynStar, _, _) => {
 +            // FIXME(dyn-star)
 +            unimplemented!()
 +        },
 +        // binops are fine on integers
 +        Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
 +            check_operand(tcx, lhs, span, body)?;
 +            check_operand(tcx, rhs, span, body)?;
 +            let ty = lhs.ty(body, tcx);
 +            if ty.is_integral() || ty.is_bool() || ty.is_char() {
 +                Ok(())
 +            } else {
 +                Err((
 +                    span,
 +                    "only int, `bool` and `char` operations are stable in const fn".into(),
 +                ))
 +            }
 +        },
 +        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
 +        Rvalue::UnaryOp(_, operand) => {
 +            let ty = operand.ty(body, tcx);
 +            if ty.is_integral() || ty.is_bool() {
 +                check_operand(tcx, operand, span, body)
 +            } else {
 +                Err((span, "only int and `bool` operations are stable in const fn".into()))
 +            }
 +        },
 +        Rvalue::Aggregate(_, operands) => {
 +            for operand in operands {
 +                check_operand(tcx, operand, span, body)?;
 +            }
 +            Ok(())
 +        },
 +    }
 +}
 +
 +fn check_statement<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    body: &Body<'tcx>,
 +    def_id: DefId,
 +    statement: &Statement<'tcx>,
 +) -> McfResult {
 +    let span = statement.source_info.span;
 +    match &statement.kind {
 +        StatementKind::Assign(box (place, rval)) => {
 +            check_place(tcx, *place, span, body)?;
 +            check_rvalue(tcx, body, def_id, rval, span)
 +        },
 +
 +        StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
 +        // just an assignment
 +        StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
 +            check_place(tcx, **place, span, body)
 +        },
 +
 +        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
 +
 +        StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
 +            rustc_middle::mir::CopyNonOverlapping { dst, src, count },
 +        )) => {
 +            check_operand(tcx, dst, span, body)?;
 +            check_operand(tcx, src, span, body)?;
 +            check_operand(tcx, count, span, body)
 +        },
 +        // These are all NOPs
 +        StatementKind::StorageLive(_)
 +        | StatementKind::StorageDead(_)
 +        | StatementKind::Retag { .. }
 +        | StatementKind::AscribeUserType(..)
 +        | StatementKind::Coverage(..)
 +        | StatementKind::Nop => Ok(()),
 +    }
 +}
 +
 +fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
 +    match operand {
 +        Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
 +        Operand::Constant(c) => match c.check_static_ptr(tcx) {
 +            Some(_) => Err((span, "cannot access `static` items in const fn".into())),
 +            None => Ok(()),
 +        },
 +    }
 +}
 +
 +fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
 +    let mut cursor = place.projection.as_ref();
 +    while let [ref proj_base @ .., elem] = *cursor {
 +        cursor = proj_base;
 +        match elem {
 +            ProjectionElem::Field(..) => {
 +                let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
 +                if let Some(def) = base_ty.ty_adt_def() {
 +                    // No union field accesses in `const fn`
 +                    if def.is_union() {
 +                        return Err((span, "accessing union fields is unstable".into()));
 +                    }
 +                }
 +            },
 +            ProjectionElem::ConstantIndex { .. }
 +            | ProjectionElem::OpaqueCast(..)
 +            | ProjectionElem::Downcast(..)
 +            | ProjectionElem::Subslice { .. }
 +            | ProjectionElem::Deref
 +            | ProjectionElem::Index(_) => {},
 +        }
 +    }
 +
 +    Ok(())
 +}
 +
 +fn check_terminator<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    body: &Body<'tcx>,
 +    terminator: &Terminator<'tcx>,
 +    msrv: &Msrv,
 +) -> McfResult {
 +    let span = terminator.source_info.span;
 +    match &terminator.kind {
 +        TerminatorKind::FalseEdge { .. }
 +        | TerminatorKind::FalseUnwind { .. }
 +        | TerminatorKind::Goto { .. }
 +        | TerminatorKind::Return
 +        | TerminatorKind::Resume
 +        | TerminatorKind::Unreachable => Ok(()),
 +
 +        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
 +        TerminatorKind::DropAndReplace { place, value, .. } => {
 +            check_place(tcx, *place, span, body)?;
 +            check_operand(tcx, value, span, body)
 +        },
 +
++        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 +
 +        TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
 +        TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
 +            Err((span, "const fn generators are unstable".into()))
 +        },
 +
 +        TerminatorKind::Call {
 +            func,
 +            args,
 +            from_hir_call: _,
 +            destination: _,
 +            target: _,
 +            cleanup: _,
 +            fn_span: _,
 +        } => {
 +            let fn_ty = func.ty(body, tcx);
 +            if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
 +                if !is_const_fn(tcx, fn_def_id, msrv) {
 +                    return Err((
 +                        span,
 +                        format!(
 +                            "can only call other `const fn` within a `const fn`, \
 +                             but `{func:?}` is not stable as `const fn`",
 +                        )
 +                        .into(),
 +                    ));
 +                }
 +
 +                // HACK: This is to "unstabilize" the `transmute` intrinsic
 +                // within const fns. `transmute` is allowed in all other const contexts.
 +                // This won't really scale to more intrinsics or functions. Let's allow const
 +                // transmutes in const fn before we add more hacks to this.
 +                if tcx.is_intrinsic(fn_def_id) && tcx.item_name(fn_def_id) == sym::transmute {
 +                    return Err((
 +                        span,
 +                        "can only call `transmute` from const items, not `const fn`".into(),
 +                    ));
 +                }
 +
 +                check_operand(tcx, func, span, body)?;
 +
 +                for arg in args {
 +                    check_operand(tcx, arg, span, body)?;
 +                }
 +                Ok(())
 +            } else {
 +                Err((span, "can only call other const fns within const fn".into()))
 +            }
 +        },
 +
 +        TerminatorKind::Assert {
 +            cond,
 +            expected: _,
 +            msg: _,
 +            target: _,
 +            cleanup: _,
 +        } => check_operand(tcx, cond, span, body),
 +
 +        TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
 +    }
 +}
 +
 +fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
 +    tcx.is_const_fn(def_id)
 +        && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
 +            if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
 +                // Checking MSRV is manually necessary because `rustc` has no such concept. This entire
 +                // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
 +                // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
 +
 +                // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver`
 +                // doesn't accept                  the `-dev` version number so we have to strip it
 +                // off.
 +                let short_version = since
 +                    .as_str()
 +                    .split('-')
 +                    .next()
 +                    .expect("rustc_attr::StabilityLevel::Stable::since` is empty");
 +
 +                let since = rustc_span::Symbol::intern(short_version);
 +
 +                msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
 +                    panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
 +                }))
 +            } else {
 +                // Unstable const fn with the feature enabled.
 +                msrv.current().is_none()
 +            }
 +        })
 +}
index a6bcb134d408096099ddd5d13263a68e28688fa1,0000000000000000000000000000000000000000..2773da70d7880c2b387b96bfebabe33963051adb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1093 -1,0 +1,1107 @@@
-     self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
-     AliasTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
 +//! Util methods for [`rustc_middle::ty`]
 +
 +#![allow(clippy::module_name_repetitions)]
 +
 +use core::ops::ControlFlow;
 +use rustc_ast::ast::Mutability;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_hir as hir;
 +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
 +use rustc_infer::infer::{
 +    type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
 +    TyCtxtInferExt,
 +};
 +use rustc_lint::LateContext;
 +use rustc_middle::mir::interpret::{ConstValue, Scalar};
 +use rustc_middle::ty::{
- // Checks if the given type implements copy.
++    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
++    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
 +    VariantDef, VariantDiscr,
 +};
 +use rustc_middle::ty::{GenericArg, GenericArgKind};
 +use rustc_span::symbol::Ident;
 +use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 +use rustc_target::abi::{Size, VariantIdx};
 +use rustc_trait_selection::infer::InferCtxtExt;
 +use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 +use std::iter;
 +
 +use crate::{match_def_path, path_res, paths};
 +
-     ty.walk().any(|inner| match inner.unpack() {
-         GenericArgKind::Type(inner_ty) => {
-             if inner_ty == needle {
-                 return true;
-             }
++/// Checks if the given type implements copy.
 +pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
 +}
 +
 +/// This checks whether a given type is known to implement Debug.
 +pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    cx.tcx
 +        .get_diagnostic_item(sym::Debug)
 +        .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
 +}
 +
 +/// Checks whether a type can be partially moved.
 +pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    if has_drop(cx, ty) || is_copy(cx, ty) {
 +        return false;
 +    }
 +    match ty.kind() {
 +        ty::Param(_) => false,
 +        ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))),
 +        _ => true,
 +    }
 +}
 +
 +/// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 +/// constructor.
 +pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
 +    ty.walk().any(|inner| match inner.unpack() {
 +        GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt),
 +        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
 +    })
 +}
 +
 +/// Walks into `ty` and returns `true` if any inner type is an instance of the given type, or adt
 +/// constructor of the same type.
 +///
 +/// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
 +/// will also return `true`.
 +pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
-             if inner_ty.ty_adt_def() == needle.ty_adt_def() {
-                 return true;
-             }
++    fn contains_ty_adt_constructor_opaque_inner<'tcx>(
++        cx: &LateContext<'tcx>,
++        ty: Ty<'tcx>,
++        needle: Ty<'tcx>,
++        seen: &mut FxHashSet<DefId>,
++    ) -> bool {
++        ty.walk().any(|inner| match inner.unpack() {
++            GenericArgKind::Type(inner_ty) => {
++                if inner_ty == needle {
++                    return true;
++                }
 +
-             if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
-                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                     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`.
-                         ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
-                             if trait_predicate
-                                 .trait_ref
-                                 .substs
-                                 .types()
-                                 .skip(1) // Skip the implicit `Self` generic parameter
-                                 .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
-                             {
-                                 return true;
-                             }
-                         },
-                         // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
-                         // so we check the term for `U`.
-                         ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
-                             if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
-                                 if contains_ty_adt_constructor_opaque(cx, ty, needle) {
++                if inner_ty.ty_adt_def() == needle.ty_adt_def() {
++                    return true;
++                }
 +
-                             };
-                         },
-                         _ => (),
++                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
++                    if !seen.insert(def_id) {
++                        return false;
++                    }
++
++                    for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
++                        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`.
++                            ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
++                                if trait_predicate
++                                    .trait_ref
++                                    .substs
++                                    .types()
++                                    .skip(1) // Skip the implicit `Self` generic parameter
++                                    .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
++                                {
 +                                    return true;
 +                                }
-             }
++                            },
++                            // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
++                            // so we check the term for `U`.
++                            ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
++                                if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
++                                    if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
++                                        return true;
++                                    }
++                                };
++                            },
++                            _ => (),
++                        }
 +                    }
 +                }
-             false
-         },
-         GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-     })
 +
-         ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
++                false
++            },
++            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
++        })
++    }
++
++    // A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not
++    // visited twice.
++    let mut seen = FxHashSet::default();
++    contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen)
 +}
 +
 +/// Resolves `<T as Iterator>::Item` for `T`
 +/// Do not invoke without first verifying that the type implements `Iterator`
 +pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 +    cx.tcx
 +        .get_diagnostic_item(sym::Iterator)
 +        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
 +}
 +
 +/// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
 +/// implements a trait marked with a diagnostic item use [`implements_trait`].
 +///
 +/// For a further exploitation what diagnostic items are see [diagnostic items] in
 +/// rustc-dev-guide.
 +///
 +/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
 +pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.get_diagnostic_name(adt.did()),
 +        _ => None,
 +    }
 +}
 +
 +/// Returns true if ty has `iter` or `iter_mut` methods
 +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> {
 +    // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
 +    // exists and has the desired signature. Unfortunately FnCtxt is not exported
 +    // so we can't use its `lookup_method` method.
 +    let into_iter_collections: &[Symbol] = &[
 +        sym::Vec,
 +        sym::Option,
 +        sym::Result,
 +        sym::BTreeMap,
 +        sym::BTreeSet,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::BinaryHeap,
 +        sym::HashSet,
 +        sym::HashMap,
 +        sym::PathBuf,
 +        sym::Path,
 +        sym::Receiver,
 +    ];
 +
 +    let ty_to_check = match probably_ref_ty.kind() {
 +        ty::Ref(_, ty_to_check, _) => *ty_to_check,
 +        _ => probably_ref_ty,
 +    };
 +
 +    let def_id = match ty_to_check.kind() {
 +        ty::Array(..) => return Some(sym::array),
 +        ty::Slice(..) => return Some(sym::slice),
 +        ty::Adt(adt, _) => adt.did(),
 +        _ => return None,
 +    };
 +
 +    for &name in into_iter_collections {
 +        if cx.tcx.is_diagnostic_item(name, def_id) {
 +            return Some(cx.tcx.item_name(def_id));
 +        }
 +    }
 +    None
 +}
 +
 +/// Checks whether a type implements a trait.
 +/// The function returns false in case the type contains an inference variable.
 +///
 +/// See:
 +/// * [`get_trait_def_id`](super::get_trait_def_id) to get a trait [`DefId`].
 +/// * [Common tools for writing lints] for an example how to use this function and other options.
 +///
 +/// [Common tools for writing lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md#checking-if-a-type-implements-a-specific-trait
 +pub fn implements_trait<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_id: DefId,
 +    ty_params: &[GenericArg<'tcx>],
 +) -> bool {
 +    implements_trait_with_env(
 +        cx.tcx,
 +        cx.param_env,
 +        ty,
 +        trait_id,
 +        ty_params.iter().map(|&arg| Some(arg)),
 +    )
 +}
 +
 +/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
 +pub fn implements_trait_with_env<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    param_env: ParamEnv<'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_id: DefId,
 +    ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
 +) -> bool {
 +    // Clippy shouldn't have infer types
 +    assert!(!ty.needs_infer());
 +
 +    let ty = tcx.erase_regions(ty);
 +    if ty.has_escaping_bound_vars() {
 +        return false;
 +    }
 +    let infcx = tcx.infer_ctxt().build();
 +    let orig = TypeVariableOrigin {
 +        kind: TypeVariableOriginKind::MiscVariable,
 +        span: DUMMY_SP,
 +    };
 +    let ty_params = tcx.mk_substs(
 +        ty_params
 +            .into_iter()
 +            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
 +    );
 +    infcx
 +        .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
 +        .must_apply_modulo_regions()
 +}
 +
 +/// Checks whether this type implements `Drop`.
 +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.ty_adt_def() {
 +        Some(def) => def.has_dtor(cx.tcx),
 +        None => false,
 +    }
 +}
 +
 +// Returns whether the type has #[must_use] attribute
 +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
 +        ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
 +        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
 +            // for the Array case we don't need to care for the len == 0 case
 +            // because we don't want to lint functions returning empty arrays
 +            is_must_use_ty(cx, *ty)
 +        },
 +        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) {
 +                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;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        ty::Dynamic(binder, _, _) => {
 +            for predicate in binder.iter() {
 +                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
 +                    if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        _ => false,
 +    }
 +}
 +
 +// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
 +// this function can be removed once the `normalize` method does not panic when normalization does
 +// not succeed
 +/// Checks if `Ty` is normalizable. This function is useful
 +/// to avoid crashes on `layout_of`.
 +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
 +    is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
 +}
 +
 +fn is_normalizable_helper<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    param_env: ty::ParamEnv<'tcx>,
 +    ty: Ty<'tcx>,
 +    cache: &mut FxHashMap<Ty<'tcx>, bool>,
 +) -> bool {
 +    if let Some(&cached_result) = cache.get(&ty) {
 +        return cached_result;
 +    }
 +    // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
 +    cache.insert(ty, false);
 +    let infcx = cx.tcx.infer_ctxt().build();
 +    let cause = rustc_middle::traits::ObligationCause::dummy();
 +    let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
 +        match ty.kind() {
 +            ty::Adt(def, substs) => def.variants().iter().all(|variant| {
 +                variant
 +                    .fields
 +                    .iter()
 +                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
 +            }),
 +            _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
 +                GenericArgKind::Type(inner_ty) if inner_ty != ty => {
 +                    is_normalizable_helper(cx, param_env, inner_ty, cache)
 +                },
 +                _ => true, // if inner_ty == ty, we've already checked it
 +            }),
 +        }
 +    } else {
 +        false
 +    };
 +    cache.insert(ty, result);
 +    result
 +}
 +
 +/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
 +/// integer or floating-point number type). For checking aggregation of primitive types (e.g.
 +/// tuples and slices of primitive type) see `is_recursively_primitive_type`
 +pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool {
 +    matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_))
 +}
 +
 +/// Returns `true` if the given type is a primitive (a `bool` or `char`, any integer or
 +/// floating-point number type, a `str`, or an array, slice, or tuple of those types).
 +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 +    match *ty.kind() {
 +        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
 +        ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
 +        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
 +        ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is a reference equals to a diagnostic item
 +pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind() {
 +        ty::Ref(_, ref_ty, _) => match ref_ty.kind() {
 +            ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
 +            _ => false,
 +        },
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a diagnostic item. To check if a type implements a
 +/// trait marked with a diagnostic item use [`implements_trait`].
 +///
 +/// For a further exploitation what diagnostic items are see [diagnostic items] in
 +/// rustc-dev-guide.
 +///
 +/// ---
 +///
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +///
 +/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
 +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a lang item.
 +///
 +/// Returns `false` if the `LangItem` is not defined.
 +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.lang_items().get(lang_item) == Some(adt.did()),
 +        _ => false,
 +    }
 +}
 +
 +/// Return `true` if the passed `typ` is `isize` or `usize`.
 +pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
 +    matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 +}
 +
 +/// Checks if type is struct, enum or union type with the given def path.
 +///
 +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => match_def_path(cx, adt.did(), path),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the drop order for a type matters. Some std types implement drop solely to
 +/// deallocate memory. For these types, and composites containing them, changing the drop order
 +/// won't result in any observable side effects.
 +pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
 +        if !seen.insert(ty) {
 +            return false;
 +        }
 +        if !ty.has_significant_drop(cx.tcx, cx.param_env) {
 +            false
 +        }
 +        // Check for std types which implement drop, but only for memory allocation.
 +        else if is_type_lang_item(cx, ty, LangItem::OwnedBox)
 +            || matches!(
 +                get_type_diagnostic_name(cx, ty),
 +                Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type)
 +            )
 +            || match_type(cx, ty, &paths::WEAK_RC)
 +            || match_type(cx, ty, &paths::WEAK_ARC)
 +        {
 +            // Check all of the generic arguments.
 +            if let ty::Adt(_, subs) = ty.kind() {
 +                subs.types().any(|ty| needs_ordered_drop_inner(cx, ty, seen))
 +            } else {
 +                true
 +            }
 +        } else if !cx
 +            .tcx
 +            .lang_items()
 +            .drop_trait()
 +            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
 +        {
 +            // This type doesn't implement drop, so no side effects here.
 +            // Check if any component type has any.
 +            match ty.kind() {
 +                ty::Tuple(fields) => fields.iter().any(|ty| needs_ordered_drop_inner(cx, ty, seen)),
 +                ty::Array(ty, _) => needs_ordered_drop_inner(cx, *ty, seen),
 +                ty::Adt(adt, subs) => adt
 +                    .all_fields()
 +                    .map(|f| f.ty(cx.tcx, subs))
 +                    .any(|ty| needs_ordered_drop_inner(cx, ty, seen)),
 +                _ => true,
 +            }
 +        } else {
 +            true
 +        }
 +    }
 +
 +    needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 +}
 +
 +/// Peels off all references on the type. Returns the underlying type and the number of references
 +/// removed.
 +pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
 +        if let ty::Ref(_, ty, _) = ty.kind() {
 +            peel(*ty, count + 1)
 +        } else {
 +            (ty, count)
 +        }
 +    }
 +    peel(ty, 0)
 +}
 +
 +/// Peels off all references on the type. Returns the underlying type, the number of references
 +/// removed, and whether the pointer is ultimately mutable or not.
 +pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
 +    fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
 +        match ty.kind() {
 +            ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability),
 +            ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not),
 +            _ => (ty, count, mutability),
 +        }
 +    }
 +    f(ty, 0, Mutability::Mut)
 +}
 +
 +/// Returns `true` if the given type is an `unsafe` function.
 +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
 +        _ => false,
 +    }
 +}
 +
 +/// Returns the base type for HIR references and pointers.
 +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 +    match ty.kind {
 +        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
 +        _ => ty,
 +    }
 +}
 +
 +/// Returns the base type for references and raw pointers, and count reference
 +/// depth.
 +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
 +        match ty.kind() {
 +            ty::Ref(_, ty, _) => inner(*ty, depth + 1),
 +            _ => (ty, depth),
 +        }
 +    }
 +    inner(ty, 0)
 +}
 +
 +/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
 +/// otherwise returns `false`
 +pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 +    match (&a.kind(), &b.kind()) {
 +        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
 +            if did_a != did_b {
 +                return false;
 +            }
 +
 +            substs_a
 +                .iter()
 +                .zip(substs_b.iter())
 +                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
 +                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
 +                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
 +                        same_type_and_consts(type_a, type_b)
 +                    },
 +                    _ => true,
 +                })
 +        },
 +        _ => a == b,
 +    }
 +}
 +
 +/// Checks if a given type looks safe to be uninitialized.
 +pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 +    match *ty.kind() {
 +        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
 +        ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
 +        ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()),
 +        _ => false,
 +    }
 +}
 +
 +/// Gets an iterator over all predicates which apply to the given item.
 +pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
 +    let mut next_id = Some(id);
 +    iter::from_fn(move || {
 +        next_id.take().map(|id| {
 +            let preds = tcx.predicates_of(id);
 +            next_id = preds.parent;
 +            preds.predicates.iter()
 +        })
 +    })
 +    .flatten()
 +}
 +
 +/// A signature for a function like type.
 +#[derive(Clone, Copy)]
 +pub enum ExprFnSig<'tcx> {
 +    Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
 +    Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
 +    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
 +}
 +impl<'tcx> ExprFnSig<'tcx> {
 +    /// Gets the argument type at the given offset. This will return `None` when the index is out of
 +    /// bounds only for variadic functions, otherwise this will panic.
 +    pub fn input(self, i: usize) -> Option<Binder<'tcx, Ty<'tcx>>> {
 +        match self {
 +            Self::Sig(sig, _) => {
 +                if sig.c_variadic() {
 +                    sig.inputs().map_bound(|inputs| inputs.get(i).copied()).transpose()
 +                } else {
 +                    Some(sig.input(i))
 +                }
 +            },
 +            Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
 +            Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
 +        }
 +    }
 +
 +    /// Gets the argument type at the given offset. For closures this will also get the type as
 +    /// written. This will return `None` when the index is out of bounds only for variadic
 +    /// functions, otherwise this will panic.
 +    pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> {
 +        match self {
 +            Self::Sig(sig, _) => {
 +                if sig.c_variadic() {
 +                    sig.inputs()
 +                        .map_bound(|inputs| inputs.get(i).copied())
 +                        .transpose()
 +                        .map(|arg| (None, arg))
 +                } else {
 +                    Some((None, sig.input(i)))
 +                }
 +            },
 +            Self::Closure(decl, sig) => Some((
 +                decl.and_then(|decl| decl.inputs.get(i)),
 +                sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
 +            )),
 +            Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
 +        }
 +    }
 +
 +    /// Gets the result type, if one could be found. Note that the result type of a trait may not be
 +    /// specified.
 +    pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
 +        match self {
 +            Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
 +            Self::Trait(_, output, _) => output,
 +        }
 +    }
 +
 +    pub fn predicates_id(&self) -> Option<DefId> {
 +        if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
 +            id
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// If the expression is function like, get the signature for it.
 +pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
 +    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
 +        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
 +    } else {
 +        ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
 +    }
 +}
 +
 +/// If the type is function like, get the signature for it.
 +pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
 +    if ty.is_box() {
 +        return ty_sig(cx, ty.boxed_ty());
 +    }
 +    match *ty.kind() {
 +        ty::Closure(id, subs) => {
 +            let decl = id
 +                .as_local()
 +                .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
 +            Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
 +        },
 +        ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-                 if Some(p.projection_ty.def_id) == lang_items.fn_once_output()
-                     && p.projection_ty.self_ty() == ty =>
++        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
++            sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
++        },
 +        ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
 +        ty::Dynamic(bounds, _, _) => {
 +            let lang_items = cx.tcx.lang_items();
 +            match bounds.principal() {
 +                Some(bound)
 +                    if Some(bound.def_id()) == lang_items.fn_trait()
 +                        || Some(bound.def_id()) == lang_items.fn_once_trait()
 +                        || Some(bound.def_id()) == lang_items.fn_mut_trait() =>
 +                {
 +                    let output = bounds
 +                        .projection_bounds()
 +                        .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
 +                        .map(|p| p.map_bound(|p| p.term.ty().unwrap()));
 +                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
 +                },
 +                _ => None,
 +            }
 +        },
 +        ty::Alias(ty::Projection, proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
 +            Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
 +            _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
 +        },
 +        ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
 +        _ => None,
 +    }
 +}
 +
 +fn sig_from_bounds<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: Ty<'tcx>,
 +    predicates: &'tcx [Predicate<'tcx>],
 +    predicates_id: Option<DefId>,
 +) -> Option<ExprFnSig<'tcx>> {
 +    let mut inputs = None;
 +    let mut output = None;
 +    let lang_items = cx.tcx.lang_items();
 +
 +    for pred in predicates {
 +        match pred.kind().skip_binder() {
 +            PredicateKind::Clause(ty::Clause::Trait(p))
 +                if (lang_items.fn_trait() == Some(p.def_id())
 +                    || lang_items.fn_mut_trait() == Some(p.def_id())
 +                    || lang_items.fn_once_trait() == Some(p.def_id()))
 +                    && p.self_ty() == ty =>
 +            {
 +                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
 +                if inputs.map_or(false, |inputs| i != inputs) {
 +                    // Multiple different fn trait impls. Is this even allowed?
 +                    return None;
 +                }
 +                inputs = Some(i);
 +            },
 +            PredicateKind::Clause(ty::Clause::Projection(p))
-         Some(tcx.mk_alias_ty(
-             assoc_item.def_id,
-             substs,
-         ))
++                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
 +            {
 +                if output.is_some() {
 +                    // Multiple different fn trait impls. Is this even allowed?
 +                    return None;
 +                }
 +                output = Some(pred.kind().rebind(p.term.ty().unwrap()));
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
 +}
 +
 +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
 +    let mut inputs = None;
 +    let mut output = None;
 +    let lang_items = cx.tcx.lang_items();
 +
 +    for (pred, _) in cx
 +        .tcx
 +        .bound_explicit_item_bounds(ty.def_id)
 +        .subst_iter_copied(cx.tcx, ty.substs)
 +    {
 +        match pred.kind().skip_binder() {
 +            PredicateKind::Clause(ty::Clause::Trait(p))
 +                if (lang_items.fn_trait() == Some(p.def_id())
 +                    || lang_items.fn_mut_trait() == Some(p.def_id())
 +                    || lang_items.fn_once_trait() == Some(p.def_id())) =>
 +            {
 +                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
 +
 +                if inputs.map_or(false, |inputs| inputs != i) {
 +                    // Multiple different fn trait impls. Is this even allowed?
 +                    return None;
 +                }
 +                inputs = Some(i);
 +            },
 +            PredicateKind::Clause(ty::Clause::Projection(p))
 +                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() =>
 +            {
 +                if output.is_some() {
 +                    // Multiple different fn trait impls. Is this even allowed?
 +                    return None;
 +                }
 +                output = pred.kind().rebind(p.term.ty()).transpose();
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
 +}
 +
 +#[derive(Clone, Copy)]
 +pub enum EnumValue {
 +    Unsigned(u128),
 +    Signed(i128),
 +}
 +impl core::ops::Add<u32> for EnumValue {
 +    type Output = Self;
 +    fn add(self, n: u32) -> Self::Output {
 +        match self {
 +            Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
 +            Self::Signed(x) => Self::Signed(x + i128::from(n)),
 +        }
 +    }
 +}
 +
 +/// Attempts to read the given constant as though it were an enum value.
 +#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
 +pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
 +    if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
 +        match tcx.type_of(id).kind() {
 +            ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
 +                1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
 +                2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
 +                4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
 +                8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
 +                16 => value.assert_bits(Size::from_bytes(16)) as i128,
 +                _ => return None,
 +            })),
 +            ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
 +                1 => value.assert_bits(Size::from_bytes(1)),
 +                2 => value.assert_bits(Size::from_bytes(2)),
 +                4 => value.assert_bits(Size::from_bytes(4)),
 +                8 => value.assert_bits(Size::from_bytes(8)),
 +                16 => value.assert_bits(Size::from_bytes(16)),
 +                _ => return None,
 +            })),
 +            _ => None,
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Gets the value of the given variant.
 +pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: AdtDef<'_>, i: VariantIdx) -> EnumValue {
 +    let variant = &adt.variant(i);
 +    match variant.discr {
 +        VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(),
 +        VariantDiscr::Relative(x) => match adt.variant((i.as_usize() - x as usize).into()).discr {
 +            VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x,
 +            VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()),
 +        },
 +    }
 +}
 +
 +/// Check if the given type is either `core::ffi::c_void`, `std::os::raw::c_void`, or one of the
 +/// platform specific `libc::<platform>::c_void` types in libc.
 +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"
 +    {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn for_each_top_level_late_bound_region<B>(
 +    ty: Ty<'_>,
 +    f: impl FnMut(BoundRegion) -> ControlFlow<B>,
 +) -> ControlFlow<B> {
 +    struct V<F> {
 +        index: u32,
 +        f: F,
 +    }
 +    impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<'tcx> for V<F> {
 +        type BreakTy = B;
 +        fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
 +            if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index {
 +                (self.f)(bound)
 +            } else {
 +                ControlFlow::Continue(())
 +            }
 +        }
 +        fn visit_binder<T: TypeVisitable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
 +            self.index += 1;
 +            let res = t.super_visit_with(self);
 +            self.index -= 1;
 +            res
 +        }
 +    }
 +    ty.visit_with(&mut V { index: 0, f })
 +}
 +
 +pub struct AdtVariantInfo {
 +    pub ind: usize,
 +    pub size: u64,
 +
 +    /// (ind, size)
 +    pub fields_size: Vec<(usize, u64)>,
 +}
 +
 +impl AdtVariantInfo {
 +    /// Returns ADT variants ordered by size
 +    pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: &'tcx List<GenericArg<'tcx>>) -> Vec<Self> {
 +        let mut variants_size = adt
 +            .variants()
 +            .iter()
 +            .enumerate()
 +            .map(|(i, variant)| {
 +                let mut fields_size = variant
 +                    .fields
 +                    .iter()
 +                    .enumerate()
 +                    .map(|(i, f)| (i, approx_ty_size(cx, f.ty(cx.tcx, subst))))
 +                    .collect::<Vec<_>>();
 +                fields_size.sort_by(|(_, a_size), (_, b_size)| (a_size.cmp(b_size)));
 +
 +                Self {
 +                    ind: i,
 +                    size: fields_size.iter().map(|(_, size)| size).sum(),
 +                    fields_size,
 +                }
 +            })
 +            .collect::<Vec<_>>();
 +        variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
 +        variants_size
 +    }
 +}
 +
 +/// Gets the struct or enum variant from the given `Res`
 +pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
 +    match res {
 +        Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
 +        Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
 +        Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
 +        Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
 +            let var_id = cx.tcx.parent(id);
 +            Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
 +        },
 +        Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()),
 +        _ => None,
 +    }
 +}
 +
 +/// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
 +pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool {
 +    let ty::Param(ty) = *ty.kind() else {
 +        return false;
 +    };
 +    let lang = tcx.lang_items();
 +    let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id))
 +        = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
 +    else {
 +        return false;
 +    };
 +    predicates
 +        .iter()
 +        .try_fold(false, |found, p| {
 +            if let PredicateKind::Clause(ty::Clause::Trait(p)) = p.kind().skip_binder()
 +            && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
 +            && ty.index == self_ty.index
 +        {
 +            // This should use `super_traits_of`, but that's a private function.
 +            if p.trait_ref.def_id == fn_once_id {
 +                return Some(true);
 +            } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
 +                return None;
 +            }
 +        }
 +            Some(found)
 +        })
 +        .unwrap_or(false)
 +}
 +
 +/// Comes up with an "at least" guesstimate for the type's size, not taking into
 +/// account the layout of type parameters.
 +pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
 +    use rustc_middle::ty::layout::LayoutOf;
 +    if !is_normalizable(cx, cx.param_env, ty) {
 +        return 0;
 +    }
 +    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::Array(t, n)) => {
 +            n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
 +        },
 +        (Err(_), ty::Adt(def, subst)) if def.is_struct() => def
 +            .variants()
 +            .iter()
 +            .map(|v| {
 +                v.fields
 +                    .iter()
 +                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
 +                    .sum::<u64>()
 +            })
 +            .sum(),
 +        (Err(_), ty::Adt(def, subst)) if def.is_enum() => def
 +            .variants()
 +            .iter()
 +            .map(|v| {
 +                v.fields
 +                    .iter()
 +                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
 +                    .sum::<u64>()
 +            })
 +            .max()
 +            .unwrap_or_default(),
 +        (Err(_), ty::Adt(def, subst)) if def.is_union() => def
 +            .variants()
 +            .iter()
 +            .map(|v| {
 +                v.fields
 +                    .iter()
 +                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
 +                    .max()
 +                    .unwrap_or_default()
 +            })
 +            .max()
 +            .unwrap_or_default(),
 +        (Err(_), _) => 0,
 +    }
 +}
 +
 +/// Makes the projection type for the named associated type in the given impl or trait impl.
 +///
 +/// This function is for associated types which are "known" to exist, 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 the named associated type exists, the correct number of
 +/// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
 +/// constant or type). This will not check if type normalization would succeed.
 +pub fn make_projection<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    container_id: DefId,
 +    assoc_ty: Symbol,
 +    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 +) -> Option<AliasTy<'tcx>> {
 +    fn helper<'tcx>(
 +        tcx: TyCtxt<'tcx>,
 +        container_id: DefId,
 +        assoc_ty: Symbol,
 +        substs: SubstsRef<'tcx>,
 +    ) -> Option<AliasTy<'tcx>> {
 +        let Some(assoc_item) = tcx
 +            .associated_items(container_id)
 +            .find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id)
 +        else {
 +            debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`");
 +            return None;
 +        };
 +        #[cfg(debug_assertions)]
 +        {
 +            let generics = tcx.generics_of(assoc_item.def_id);
 +            let generic_count = generics.parent_count + generics.params.len();
 +            let params = generics
 +                .parent
 +                .map_or([].as_slice(), |id| &*tcx.generics_of(id).params)
 +                .iter()
 +                .chain(&generics.params)
 +                .map(|x| &x.kind);
 +
 +            debug_assert!(
 +                generic_count == substs.len(),
 +                "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n\
 +                    note: the expected parameters are: {:#?}\n\
 +                    the given arguments are: `{substs:#?}`",
 +                assoc_item.def_id,
 +                substs.len(),
 +                params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
 +            );
 +
 +            if let Some((idx, (param, arg))) = params
 +                .clone()
 +                .zip(substs.iter().map(GenericArg::unpack))
 +                .enumerate()
 +                .find(|(_, (param, arg))| {
 +                    !matches!(
 +                        (param, arg),
 +                        (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
 +                            | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
 +                            | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
 +                    )
 +                })
 +            {
 +                debug_assert!(
 +                    false,
 +                    "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
 +                        note: the expected parameters are {:#?}\n\
 +                        the given arguments are {substs:#?}",
 +                    param.descr(),
 +                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
 +                );
 +            }
 +        }
 +
++        Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
 +    }
 +    helper(
 +        tcx,
 +        container_id,
 +        assoc_ty,
 +        tcx.mk_substs(substs.into_iter().map(Into::into)),
 +    )
 +}
 +
 +/// Normalizes the named associated type in the given impl or trait impl.
 +///
 +/// 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
 +/// succeeds as well as everything checked by `make_projection`.
 +pub fn make_normalized_projection<'tcx>(
 +    tcx: TyCtxt<'tcx>,
 +    param_env: ParamEnv<'tcx>,
 +    container_id: DefId,
 +    assoc_ty: Symbol,
 +    substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
 +) -> Option<Ty<'tcx>> {
 +    fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
 +        #[cfg(debug_assertions)]
 +        if let Some((i, subst)) = ty
 +            .substs
 +            .iter()
 +            .enumerate()
 +            .find(|(_, subst)| subst.has_late_bound_regions())
 +        {
 +            debug_assert!(
 +                false,
 +                "substs contain late-bound region at index `{i}` which can't be normalized.\n\
 +                    use `TyCtxt::erase_late_bound_regions`\n\
 +                    note: subst is `{subst:#?}`",
 +            );
 +            return None;
 +        }
 +        match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) {
 +            Ok(ty) => Some(ty),
 +            Err(e) => {
 +                debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
 +                None
 +            },
 +        }
 +    }
 +    helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
 +}
index 082570f1fe5d87a1924f3503a02ce5fcf6931b4e,0000000000000000000000000000000000000000..c01e1062cb5445c2557a08692ff35eb79212db2d
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- version = "0.1.67"
 +[package]
 +name = "declare_clippy_lint"
++version = "0.1.68"
 +edition = "2021"
 +publish = false
 +
 +[lib]
 +proc-macro = true
 +
 +[dependencies]
 +itertools = "0.10.1"
 +quote = "1.0.21"
 +syn = "1.0.100"
 +
 +[features]
 +deny-warnings = []
index 19fee38db46e642eb18f600b1a3b7d8b6e8a814f,0000000000000000000000000000000000000000..8e21cef32abb63ff135e93acb27ef0d644e97de9
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2022-12-01"
 +[toolchain]
++channel = "nightly-2022-12-17"
 +components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1b351da2e7bceecb8f1985da3ad0a2cfe772e563
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++# Changelog
++
++## Version 0.3.0
++
++* Added `setup_version_info!();` macro for automated scripts.
++* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env`
index 89c3d6aaa89e785e15db5dd2de15d7ca69d7239e,0000000000000000000000000000000000000000..877049ae7d0ebd92d8d11d95698f89ded3698a93
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,15 @@@
- version = "0.2.1"
 +[package]
 +name = "rustc_tools_util"
++version = "0.3.0"
 +description = "small helper to generate version information for git packages"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["rustc", "tool", "git", "version", "hash"]
 +categories = ["development-tools"]
 +edition = "2018"
 +
 +[dependencies]
 +
 +[features]
 +deny-warnings = []
index e947f9c7e66ed29d7fdc0cf9e4fbc5828994fca5,0000000000000000000000000000000000000000..eefc661f96352e04d182fe016702674df122880f
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,58 @@@
- rustc_tools_util = "0.2.1"
 +# rustc_tools_util
 +
 +A small tool to help you generate version information
 +for packages installed from a git repo
 +
 +## Usage
 +
 +Add a `build.rs` file to your repo and list it in `Cargo.toml`
 +````toml
 +build = "build.rs"
 +````
 +
 +List rustc_tools_util as regular AND build dependency.
 +````toml
 +[dependencies]
- rustc_tools_util = "0.2.1"
++rustc_tools_util = "0.3.0"
 +
 +[build-dependencies]
- ````rust
++rustc_tools_util = "0.3.0"
 +````
 +
 +In `build.rs`, generate the data in your `main()`
-     println!(
-         "cargo:rustc-env=GIT_HASH={}",
-         rustc_tools_util::get_commit_hash().unwrap_or_default()
-     );
-     println!(
-         "cargo:rustc-env=COMMIT_DATE={}",
-         rustc_tools_util::get_commit_date().unwrap_or_default()
-     );
-     println!(
-         "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-         rustc_tools_util::get_channel().unwrap_or_default()
-     );
++
++```rust
 +fn main() {
- ````
++    rustc_tools_util::setup_version_info!();
 +}
- ````rust
- use rustc_tools_util::*;
++```
 +
 +Use the version information in your main.rs
- ````
 +
++```rust
 +fn show_version() {
 +    let version_info = rustc_tools_util::get_version_info!();
 +    println!("{}", version_info);
 +}
- `clippy 0.0.212 (a416c5e 2018-12-14)`
++```
++
 +This gives the following output in clippy:
++`clippy 0.1.66 (a28f3c8 2022-11-20)`
++
++## Repository
++
++This project is part of the rust-lang/rust-clippy repository. The source code
++can be found under `./rustc_tools_util/`.
 +
++The changelog for `rustc_tools_util` is available under:
++[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md)
 +
 +## License
 +
 +Copyright 2014-2022 The Rust Project Developers
 +
 +Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 +http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 +<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 +option. All files in the project carrying such notice may not be
 +copied, modified, or distributed except according to those terms.
index 01d25c53126fdefcb7460562a192deccd457aa7d,0000000000000000000000000000000000000000..4c1d8c3733df61b97582e3780118d9b2446b8de7
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,180 @@@
- use std::env;
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +
-         let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
-         let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
-         let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
-         let crate_name = String::from(env!("CARGO_PKG_NAME"));
++/// This macro creates the version string during compilation from the
++/// current environment
 +#[macro_export]
 +macro_rules! get_version_info {
 +    () => {{
-         let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
-         let commit_hash = option_env!("GIT_HASH").map(str::to_string);
-         let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
++        let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
++        let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
++        let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
++        let crate_name = String::from(std::env!("CARGO_PKG_NAME"));
 +
-         VersionInfo {
++        let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
++        let commit_hash = std::option_env!("GIT_HASH").map(str::to_string);
++        let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string);
 +
-     match env::var("CFG_RELEASE_CHANNEL") {
++        $crate::VersionInfo {
 +            major,
 +            minor,
 +            patch,
 +            host_compiler,
 +            commit_hash,
 +            commit_date,
 +            crate_name,
 +        }
 +    }};
 +}
 +
++/// This macro can be used in `build.rs` to automatically set the needed
++/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
++/// `RUSTC_RELEASE_CHANNEL`
++#[macro_export]
++macro_rules! setup_version_info {
++    () => {{
++        println!(
++            "cargo:rustc-env=GIT_HASH={}",
++            $crate::get_commit_hash().unwrap_or_default()
++        );
++        println!(
++            "cargo:rustc-env=COMMIT_DATE={}",
++            $crate::get_commit_date().unwrap_or_default()
++        );
++        println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
++    }};
++}
++
 +// some code taken and adapted from RLS and cargo
 +pub struct VersionInfo {
 +    pub major: u8,
 +    pub minor: u8,
 +    pub patch: u16,
 +    pub host_compiler: Option<String>,
 +    pub commit_hash: Option<String>,
 +    pub commit_date: Option<String>,
 +    pub crate_name: String,
 +}
 +
 +impl std::fmt::Display for VersionInfo {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        let hash = self.commit_hash.clone().unwrap_or_default();
 +        let hash_trimmed = hash.trim();
 +
 +        let date = self.commit_date.clone().unwrap_or_default();
 +        let date_trimmed = date.trim();
 +
 +        if (hash_trimmed.len() + date_trimmed.len()) > 0 {
 +            write!(
 +                f,
 +                "{} {}.{}.{} ({hash_trimmed} {date_trimmed})",
 +                self.crate_name, self.major, self.minor, self.patch,
 +            )?;
 +        } else {
 +            write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
 +        }
 +
 +        Ok(())
 +    }
 +}
 +
 +impl std::fmt::Debug for VersionInfo {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(
 +            f,
 +            "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
 +            self.crate_name, self.major, self.minor, self.patch,
 +        )?;
 +        if self.commit_hash.is_some() {
 +            write!(
 +                f,
 +                ", commit_hash: \"{}\", commit_date: \"{}\" }}",
 +                self.commit_hash.clone().unwrap_or_default().trim(),
 +                self.commit_date.clone().unwrap_or_default().trim()
 +            )?;
 +        } else {
 +            write!(f, " }}")?;
 +        }
 +
 +        Ok(())
 +    }
 +}
 +
 +#[must_use]
 +pub fn get_commit_hash() -> Option<String> {
 +    std::process::Command::new("git")
 +        .args(["rev-parse", "--short", "HEAD"])
 +        .output()
 +        .ok()
 +        .and_then(|r| String::from_utf8(r.stdout).ok())
 +}
 +
 +#[must_use]
 +pub fn get_commit_date() -> Option<String> {
 +    std::process::Command::new("git")
 +        .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
 +        .output()
 +        .ok()
 +        .and_then(|r| String::from_utf8(r.stdout).ok())
 +}
 +
 +#[must_use]
 +pub fn get_channel() -> String {
-         assert_eq!(vi.minor, 2);
-         assert_eq!(vi.patch, 1);
++    match std::env::var("CFG_RELEASE_CHANNEL") {
 +        Ok(channel) => channel,
 +        Err(_) => {
 +            // if that failed, try to ask rustc -V, do some parsing and find out
 +            match std::process::Command::new("rustc")
 +                .arg("-V")
 +                .output()
 +                .ok()
 +                .and_then(|r| String::from_utf8(r.stdout).ok())
 +            {
 +                Some(rustc_output) => {
 +                    if rustc_output.contains("beta") {
 +                        String::from("beta")
 +                    } else if rustc_output.contains("stable") {
 +                        String::from("stable")
 +                    } else {
 +                        // default to nightly if we fail to parse
 +                        String::from("nightly")
 +                    }
 +                },
 +                // default to nightly
 +                None => String::from("nightly"),
 +            }
 +        },
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +
 +    #[test]
 +    fn test_struct_local() {
 +        let vi = get_version_info!();
 +        assert_eq!(vi.major, 0);
-         assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
++        assert_eq!(vi.minor, 3);
++        assert_eq!(vi.patch, 0);
 +        assert_eq!(vi.crate_name, "rustc_tools_util");
 +        // hard to make positive tests for these since they will always change
 +        assert!(vi.commit_hash.is_none());
 +        assert!(vi.commit_date.is_none());
 +    }
 +
 +    #[test]
 +    fn test_display_local() {
 +        let vi = get_version_info!();
-             "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
++        assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0");
 +    }
 +
 +    #[test]
 +    fn test_debug_local() {
 +        let vi = get_version_info!();
 +        let s = format!("{vi:?}");
 +        assert_eq!(
 +            s,
++            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }"
 +        );
 +    }
 +}
index 9ec4df8e651b1bf3f7756656f8548f5c2ec8e9c0,0000000000000000000000000000000000000000..bcc096c570e1b7013524d3b20048903cc3d85780
mode 100644,000000..100644
--- /dev/null
@@@ -1,338 -1,0 +1,337 @@@
- use rustc_tools_util::VersionInfo;
 +#![feature(rustc_private)]
 +#![feature(let_chains)]
 +#![feature(once_cell)]
 +#![feature(lint_reasons)]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// 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;
 +
 +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`.
 +fn arg_value<'a, T: Deref<Target = str>>(
 +    args: &'a [T],
 +    find_arg: &str,
 +    pred: impl Fn(&str) -> bool,
 +) -> Option<&'a str> {
 +    let mut args = args.iter().map(Deref::deref);
 +    while let Some(arg) = args.next() {
 +        let mut arg = arg.splitn(2, '=');
 +        if arg.next() != Some(find_arg) {
 +            continue;
 +        }
 +
 +        match arg.next().or_else(|| args.next()) {
 +            Some(v) if pred(v) => return Some(v),
 +            _ => {},
 +        }
 +    }
 +    None
 +}
 +
 +#[test]
 +fn test_arg_value() {
 +    let args = &["--bar=bar", "--foobar", "123", "--foo"];
 +
 +    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
 +    assert_eq!(arg_value(args, "--bar", |_| false), None);
 +    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
 +    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
 +    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
 +    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
 +    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
 +    assert_eq!(arg_value(args, "--foobar", |p| p.contains("12")), Some("123"));
 +    assert_eq!(arg_value(args, "--foo", |_| true), None);
 +}
 +
 +fn track_clippy_args(parse_sess: &mut ParseSess, args_env_var: &Option<String>) {
 +    parse_sess.env_depinfo.get_mut().insert((
 +        Symbol::intern("CLIPPY_ARGS"),
 +        args_env_var.as_deref().map(Symbol::intern),
 +    ));
 +}
 +
 +/// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
 +/// when any of them are modified
 +fn track_files(parse_sess: &mut ParseSess, conf_path_string: Option<String>) {
 +    let file_depinfo = parse_sess.file_depinfo.get_mut();
 +
 +    // Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver`
 +    // with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine
 +    if Path::new("Cargo.toml").exists() {
 +        file_depinfo.insert(Symbol::intern("Cargo.toml"));
 +    }
 +
 +    // `clippy.toml`
 +    if let Some(path) = conf_path_string {
 +        file_depinfo.insert(Symbol::intern(&path));
 +    }
 +
 +    // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
 +    // it is rebuilt
 +    #[expect(
 +        clippy::collapsible_if,
 +        reason = "Due to a bug in let_chains this if statement can't be collapsed"
 +    )]
 +    if cfg!(debug_assertions) {
 +        if let Ok(current_exe) = env::current_exe()
 +            && let Some(current_exe) = current_exe.to_str()
 +        {
 +            file_depinfo.insert(Symbol::intern(current_exe));
 +        }
 +    }
 +}
 +
 +struct DefaultCallbacks;
 +impl rustc_driver::Callbacks for DefaultCallbacks {}
 +
 +/// This is different from `DefaultCallbacks` that it will inform Cargo to track the value of
 +/// `CLIPPY_ARGS` environment variable.
 +struct RustcCallbacks {
 +    clippy_args_var: Option<String>,
 +}
 +
 +impl rustc_driver::Callbacks for RustcCallbacks {
 +    fn config(&mut self, config: &mut interface::Config) {
 +        let clippy_args_var = self.clippy_args_var.take();
 +        config.parse_sess_created = Some(Box::new(move |parse_sess| {
 +            track_clippy_args(parse_sess, &clippy_args_var);
 +        }));
 +    }
 +}
 +
 +struct ClippyCallbacks {
 +    clippy_args_var: Option<String>,
 +}
 +
 +impl rustc_driver::Callbacks for ClippyCallbacks {
 +    // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level`
 +    #[allow(rustc::bad_opt_access)]
 +    fn config(&mut self, config: &mut interface::Config) {
 +        let conf_path = clippy_lints::lookup_conf_file();
 +        let conf_path_string = if let Ok(Some(path)) = &conf_path {
 +            path.to_str().map(String::from)
 +        } else {
 +            None
 +        };
 +
 +        let previous = config.register_lints.take();
 +        let clippy_args_var = self.clippy_args_var.take();
 +        config.parse_sess_created = Some(Box::new(move |parse_sess| {
 +            track_clippy_args(parse_sess, &clippy_args_var);
 +            track_files(parse_sess, conf_path_string);
 +        }));
 +        config.register_lints = Some(Box::new(move |sess, lint_store| {
 +            // technically we're ~guaranteed that this is none but might as well call anything that
 +            // is there already. Certainly it can't hurt.
 +            if let Some(previous) = &previous {
 +                (previous)(sess, lint_store);
 +            }
 +
 +            let conf = clippy_lints::read_conf(sess, &conf_path);
 +            clippy_lints::register_plugins(lint_store, sess, &conf);
 +            clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
 +            clippy_lints::register_renamed(lint_store);
 +        }));
 +
 +        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
 +        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
 +        // 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);
 +    }
 +}
 +
 +fn display_help() {
 +    println!(
 +        "\
 +Checks a package to catch common mistakes and improve your Rust code.
 +
 +Usage:
 +    cargo clippy [options] [--] [<opts>...]
 +
 +Common options:
 +    -h, --help               Print this message
 +        --rustc              Pass all args to rustc
 +    -V, --version            Print version info and exit
 +
 +Other options are the same as `cargo check`.
 +
 +To allow or deny a lint from the command line you can use `cargo clippy --`
 +with:
 +
 +    -W --warn OPT       Set lint warnings
 +    -A --allow OPT      Set lint allowed
 +    -D --deny OPT       Set lint denied
 +    -F --forbid OPT     Set lint forbidden
 +
 +You can use tool lints to allow or deny lints from your code, eg.:
 +
 +    #[allow(clippy::needless_lifetimes)]
 +"
 +    );
 +}
 +
 +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_errors::DEFAULT_LOCALE_RESOURCES, false);
 +    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
 +        rustc_errors::ColorConfig::Auto,
 +        None,
 +        None,
 +        fallback_bundle,
 +        false,
 +        false,
 +        None,
 +        false,
 +        false,
 +    ));
 +    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);
 +    exit(rustc_driver::catch_with_exit_code(move || {
 +        let mut orig_args: Vec<String> = env::args().collect();
 +
 +        let sys_root_env = std::env::var("SYSROOT").ok();
 +        let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| {
 +            if let Some(sys_root) = sys_root_env {
 +                args.extend(vec!["--sysroot".into(), sys_root]);
 +            };
 +        };
 +
 +        // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
 +        // for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
 +        // uses
 +        if let Some(pos) = orig_args.iter().position(|arg| arg == "--rustc") {
 +            orig_args.remove(pos);
 +            orig_args[0] = "rustc".to_string();
 +
 +            let mut args: Vec<String> = orig_args.clone();
 +            pass_sysroot_env_if_given(&mut args, sys_root_env);
 +
 +            return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
 +        }
 +
 +        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
 +            let version_info = rustc_tools_util::get_version_info!();
 +            println!("{version_info}");
 +            exit(0);
 +        }
 +
 +        // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
 +        // We're invoking the compiler programmatically, so we ignore this/
 +        let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
 +
 +        if wrapper_mode {
 +            // we still want to be able to invoke it normally though
 +            orig_args.remove(1);
 +        }
 +
 +        if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
 +            display_help();
 +            exit(0);
 +        }
 +
 +        let mut args: Vec<String> = orig_args.clone();
 +        pass_sysroot_env_if_given(&mut args, sys_root_env);
 +
 +        let mut no_deps = false;
 +        let clippy_args_var = env::var("CLIPPY_ARGS").ok();
 +        let clippy_args = clippy_args_var
 +            .as_deref()
 +            .unwrap_or_default()
 +            .split("__CLIPPY_HACKERY__")
 +            .filter_map(|s| match s {
 +                "" => None,
 +                "--no-deps" => {
 +                    no_deps = true;
 +                    None
 +                },
 +                _ => Some(s.to_string()),
 +            })
 +            .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()])
 +            .collect::<Vec<String>>();
 +
 +        // We enable Clippy if one of the following conditions is met
 +        // - IF Clippy is run on its test suite OR
 +        // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
 +        //    - IF `--no-deps` is not set (`!no_deps`) OR
 +        //    - IF `--no-deps` is set and Clippy is run on the specified primary package
 +        let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some()
 +            && arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none();
 +        let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 +
 +        let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
 +        if clippy_enabled {
 +            args.extend(clippy_args);
 +            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run()
 +        } else {
 +            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run()
 +        }
 +    }))
 +}
index d418d2daa313e75d69fb6454fc12a8e59f7e37f2,0000000000000000000000000000000000000000..7a78b32620d0bf41301fa50cf781b6a5c658bb45
mode 100644,000000..100644
--- /dev/null
@@@ -1,205 -1,0 +1,204 @@@
- use rustc_tools_util::VersionInfo;
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +
 +use std::env;
 +use std::path::PathBuf;
 +use std::process::{self, Command};
 +
 +const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
 +
 +Usage:
 +    cargo clippy [options] [--] [<opts>...]
 +
 +Common options:
 +    --no-deps                Run Clippy only on the given crate, without linting the dependencies
 +    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
 +    -h, --help               Print this message
 +    -V, --version            Print version info and exit
 +    --explain LINT           Print the documentation for a given lint
 +
 +Other options are the same as `cargo check`.
 +
 +To allow or deny a lint from the command line you can use `cargo clippy --`
 +with:
 +
 +    -W --warn OPT       Set lint warnings
 +    -A --allow OPT      Set lint allowed
 +    -D --deny OPT       Set lint denied
 +    -F --forbid OPT     Set lint forbidden
 +
 +You can use tool lints to allow or deny lints from your code, eg.:
 +
 +    #[allow(clippy::needless_lifetimes)]
 +"#;
 +
 +fn show_help() {
 +    println!("{CARGO_CLIPPY_HELP}");
 +}
 +
 +fn show_version() {
 +    let version_info = rustc_tools_util::get_version_info!();
 +    println!("{version_info}");
 +}
 +
 +pub fn main() {
 +    // Check for version and help flags even when invoked as 'cargo-clippy'
 +    if env::args().any(|a| a == "--help" || a == "-h") {
 +        show_help();
 +        return;
 +    }
 +
 +    if env::args().any(|a| a == "--version" || a == "-V") {
 +        show_version();
 +        return;
 +    }
 +
 +    if let Some(pos) = env::args().position(|a| a == "--explain") {
 +        if let Some(mut lint) = env::args().nth(pos + 1) {
 +            lint.make_ascii_lowercase();
 +            clippy_lints::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_"));
 +        } else {
 +            show_help();
 +        }
 +        return;
 +    }
 +
 +    if let Err(code) = process(env::args().skip(2)) {
 +        process::exit(code);
 +    }
 +}
 +
 +struct ClippyCmd {
 +    cargo_subcommand: &'static str,
 +    args: Vec<String>,
 +    clippy_args: Vec<String>,
 +}
 +
 +impl ClippyCmd {
 +    fn new<I>(mut old_args: I) -> Self
 +    where
 +        I: Iterator<Item = String>,
 +    {
 +        let mut cargo_subcommand = "check";
 +        let mut args = vec![];
 +        let mut clippy_args: Vec<String> = vec![];
 +
 +        for arg in old_args.by_ref() {
 +            match arg.as_str() {
 +                "--fix" => {
 +                    cargo_subcommand = "fix";
 +                    continue;
 +                },
 +                "--no-deps" => {
 +                    clippy_args.push("--no-deps".into());
 +                    continue;
 +                },
 +                "--" => break,
 +                _ => {},
 +            }
 +
 +            args.push(arg);
 +        }
 +
 +        clippy_args.append(&mut (old_args.collect()));
 +        if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") {
 +            clippy_args.push("--no-deps".into());
 +        }
 +
 +        Self {
 +            cargo_subcommand,
 +            args,
 +            clippy_args,
 +        }
 +    }
 +
 +    fn path() -> PathBuf {
 +        let mut path = env::current_exe()
 +            .expect("current executable path invalid")
 +            .with_file_name("clippy-driver");
 +
 +        if cfg!(windows) {
 +            path.set_extension("exe");
 +        }
 +
 +        path
 +    }
 +
 +    fn into_std_cmd(self) -> Command {
 +        let mut cmd = Command::new("cargo");
 +        let clippy_args: String = self
 +            .clippy_args
 +            .iter()
 +            .map(|arg| format!("{arg}__CLIPPY_HACKERY__"))
 +            .collect();
 +
 +        // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
 +        let terminal_width = termize::dimensions().map_or(0, |(w, _)| w);
 +
 +        cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path())
 +            .env("CLIPPY_ARGS", clippy_args)
 +            .env("CLIPPY_TERMINAL_WIDTH", terminal_width.to_string())
 +            .arg(self.cargo_subcommand)
 +            .args(&self.args);
 +
 +        cmd
 +    }
 +}
 +
 +fn process<I>(old_args: I) -> Result<(), i32>
 +where
 +    I: Iterator<Item = String>,
 +{
 +    let cmd = ClippyCmd::new(old_args);
 +
 +    let mut cmd = cmd.into_std_cmd();
 +
 +    let exit_status = cmd
 +        .spawn()
 +        .expect("could not run cargo")
 +        .wait()
 +        .expect("failed to wait for cargo?");
 +
 +    if exit_status.success() {
 +        Ok(())
 +    } else {
 +        Err(exit_status.code().unwrap_or(-1))
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::ClippyCmd;
 +
 +    #[test]
 +    fn fix() {
 +        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
 +        let cmd = ClippyCmd::new(args);
 +        assert_eq!("fix", cmd.cargo_subcommand);
 +        assert!(!cmd.args.iter().any(|arg| arg.ends_with("unstable-options")));
 +    }
 +
 +    #[test]
 +    fn fix_implies_no_deps() {
 +        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
 +        let cmd = ClippyCmd::new(args);
 +        assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps"));
 +    }
 +
 +    #[test]
 +    fn no_deps_not_duplicated_with_fix() {
 +        let args = "cargo clippy --fix -- --no-deps"
 +            .split_whitespace()
 +            .map(ToString::to_string);
 +        let cmd = ClippyCmd::new(args);
 +        assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1);
 +    }
 +
 +    #[test]
 +    fn check() {
 +        let args = "cargo clippy".split_whitespace().map(ToString::to_string);
 +        let cmd = ClippyCmd::new(args);
 +        assert_eq!("check", cmd.cargo_subcommand);
 +    }
 +}
index 2a240cc249b0c768f084dab5b6f220ae53a59399,0000000000000000000000000000000000000000..3ca45404e44bb88290ad846bccca89f21b88f6a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,27 @@@
- error: hardcoded path to a diagnostic item
-   --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
-    |
- LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = help: convert all references to use `sym::deref_method`
 +error: hardcoded path to a diagnostic item
 +  --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
 +   |
 +LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
 +   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: convert all references to use `sym::Deref`
 +   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 +
 +error: hardcoded path to a language item
 +  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
 +   |
 +LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
 +   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: convert all references to use `LangItem::DerefMut`
 +
++error: hardcoded path to a diagnostic item
++  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
++   |
++LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
++   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++   = help: convert all references to use `sym::deref_method`
++
 +error: aborting due to 3 previous errors
 +
index e8a023ab17643514d08d08c803d51beea762610f,0000000000000000000000000000000000000000..36db9e54a228854ac09f5953faedbc07e6ee90ec
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,118 @@@
- #[derive(Clone, Copy)]
- struct Point {
-     x: i32,
-     y: i32,
 +#![warn(clippy::arithmetic_side_effects)]
 +
 +use core::ops::{Add, Neg};
 +
- impl Add for Point {
-     type Output = Self;
++macro_rules! create {
++    ($name:ident) => {
++        #[allow(clippy::arithmetic_side_effects)]
++        #[derive(Clone, Copy)]
++        struct $name;
++
++        impl Add<$name> for $name {
++            type Output = $name;
++            fn add(self, other: $name) -> Self::Output {
++                todo!()
++            }
++        }
++
++        impl Add<i32> for $name {
++            type Output = $name;
++            fn add(self, other: i32) -> Self::Output {
++                todo!()
++            }
++        }
++
++        impl Add<$name> for i32 {
++            type Output = $name;
++            fn add(self, other: $name) -> Self::Output {
++                todo!()
++            }
++        }
++
++        impl Add<i64> for $name {
++            type Output = $name;
++            fn add(self, other: i64) -> Self::Output {
++                todo!()
++            }
++        }
++
++        impl Add<$name> for i64 {
++            type Output = $name;
++            fn add(self, other: $name) -> Self::Output {
++                todo!()
++            }
++        }
++
++        impl Neg for $name {
++            type Output = $name;
++            fn neg(self) -> Self::Output {
++                todo!()
++            }
++        }
++    };
 +}
 +
-     fn add(self, other: Self) -> Self {
-         todo!()
-     }
++create!(Foo);
++create!(Bar);
++create!(Baz);
++create!(OutOfNames);
 +
- impl Neg for Point {
-     type Output = Self;
++fn lhs_and_rhs_are_equal() {
++    // is explicitly on the list
++    let _ = OutOfNames + OutOfNames;
++    // is explicitly on the list
++    let _ = Foo + Foo;
++    // is implicitly on the list
++    let _ = Bar + Bar;
++    // not on the list
++    let _ = Baz + Baz;
 +}
 +
-     fn neg(self) -> Self::Output {
-         todo!()
-     }
++fn lhs_is_different() {
++    // is explicitly on the list
++    let _ = 1i32 + OutOfNames;
++    // is explicitly on the list
++    let _ = 1i32 + Foo;
++    // is implicitly on the list
++    let _ = 1i32 + Bar;
++    // not on the list
++    let _ = 1i32 + Baz;
 +
- fn main() {
-     let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
++    // not on the list
++    let _ = 1i64 + Foo;
++    // is implicitly on the list
++    let _ = 1i64 + Bar;
++    // not on the list
++    let _ = 1i64 + Baz;
 +}
 +
-     let point: Point = Point { x: 1, y: 0 };
-     let _ = point + point;
-     let _ = -point;
++fn rhs_is_different() {
++    // is explicitly on the list
++    let _ = OutOfNames + 1i32;
++    // is explicitly on the list
++    let _ = Foo + 1i32;
++    // is implicitly on the list
++    let _ = Bar + 1i32;
++    // not on the list
++    let _ = Baz + 1i32;
++
++    // not on the list
++    let _ = Foo + 1i64;
++    // is implicitly on the list
++    let _ = Bar + 1i64;
++    // not on the list
++    let _ = Baz + 1i64;
++}
 +
++fn unary() {
++    // is explicitly on the list
++    let _ = -OutOfNames;
++    // is specifically on the list
++    let _ = -Foo;
++    // not on the list
++    let _ = -Bar;
++    // not on the list
++    let _ = -Baz;
 +}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ad89534aa1b042c808de5d69622e32c466c288e7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,58 @@@
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:68:13
++   |
++LL |     let _ = Baz + Baz;
++   |             ^^^^^^^^^
++   |
++   = 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_allowed.rs:79:13
++   |
++LL |     let _ = 1i32 + Baz;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:82:13
++   |
++LL |     let _ = 1i64 + Foo;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:86:13
++   |
++LL |     let _ = 1i64 + Baz;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:97:13
++   |
++LL |     let _ = Baz + 1i32;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:100:13
++   |
++LL |     let _ = Foo + 1i64;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:104:13
++   |
++LL |     let _ = Baz + 1i64;
++   |             ^^^^^^^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:113:13
++   |
++LL |     let _ = -Bar;
++   |             ^^^^
++
++error: arithmetic operation that can potentially result in unexpected side-effects
++  --> $DIR/arithmetic_side_effects_allowed.rs:115:13
++   |
++LL |     let _ = -Baz;
++   |             ^^^^
++
++error: aborting due to 9 previous errors
++
index e736256f29a475564c327ccdab471bec05993d49,0000000000000000000000000000000000000000..89cbea7ecfe4728a7660a497312179bdafea4311
mode 100644,000000..100644
--- /dev/null
@@@ -1,1 -1,0 +1,11 @@@
- arithmetic-side-effects-allowed = ["Point"]
++arithmetic-side-effects-allowed = [
++    "OutOfNames"
++]
++arithmetic-side-effects-allowed-binary = [
++    ["Foo", "Foo"],
++    ["Foo", "i32"],
++    ["i32", "Foo"],
++    ["Bar", "*"],
++    ["*", "Bar"],
++]
++arithmetic-side-effects-allowed-unary = ["Foo"]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1b9384d7e3ee6092512025e92324a856aadd09a4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++suppress-restriction-lint-in-const = true
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5a2df9f6c5d912779067a1fe0ce6dcbd32a0f09f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++#![feature(inline_const)]
++#![warn(clippy::indexing_slicing)]
++// We also check the out_of_bounds_indexing lint here, because it lints similar things and
++// we want to avoid false positives.
++#![warn(clippy::out_of_bounds_indexing)]
++#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
++
++const ARR: [i32; 2] = [1, 2];
++const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
++const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
++
++const fn idx() -> usize {
++    1
++}
++const fn idx4() -> usize {
++    4
++}
++
++fn main() {
++    let x = [1, 2, 3, 4];
++    let index: usize = 1;
++    x[index];
++    x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++
++    x[0]; // Ok, should not produce stderr.
++    x[3]; // Ok, should not produce stderr.
++    x[const { idx() }]; // Ok, should not produce stderr.
++    x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
++    const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
++
++    let y = &x;
++    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
++    y[4]; // Ok, rustc will handle references too.
++
++    let v = vec![0; 5];
++    v[0];
++    v[10];
++    v[1 << 3];
++
++    const N: usize = 15; // Out of bounds
++    const M: usize = 3; // In bounds
++    x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    x[M]; // Ok, should not produce stderr.
++    v[N];
++    v[M];
++}
++
++/// An opaque integer representation
++pub struct Integer<'a> {
++    /// The underlying data
++    value: &'a [u8],
++}
++impl<'a> Integer<'a> {
++    // Check whether `self` holds a negative number or not
++    pub const fn is_negative(&self) -> bool {
++        self.value[0] & 0b1000_0000 != 0
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bc178b7e1319d4e81f9ee4303b6338d5a7e591ef
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,70 @@@
++error[E0080]: evaluation of `main::{constant#3}` failed
++  --> $DIR/test.rs:31:14
++   |
++LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
++   |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
++
++note: erroneous constant used
++  --> $DIR/test.rs:31:5
++   |
++LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
++   |     ^^^^^^^^^^^^^^^^^^^^^^
++
++error: indexing may panic
++  --> $DIR/test.rs:22:5
++   |
++LL |     x[index];
++   |     ^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
++
++error: indexing may panic
++  --> $DIR/test.rs:38:5
++   |
++LL |     v[0];
++   |     ^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++
++error: indexing may panic
++  --> $DIR/test.rs:39:5
++   |
++LL |     v[10];
++   |     ^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++
++error: indexing may panic
++  --> $DIR/test.rs:40:5
++   |
++LL |     v[1 << 3];
++   |     ^^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++
++error: indexing may panic
++  --> $DIR/test.rs:46:5
++   |
++LL |     v[N];
++   |     ^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++
++error: indexing may panic
++  --> $DIR/test.rs:47:5
++   |
++LL |     v[M];
++   |     ^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++
++error[E0080]: evaluation of constant value failed
++  --> $DIR/test.rs:10:24
++   |
++LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
++   |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
++
++error: aborting due to 8 previous errors
++
++For more information about this error, try `rustc --explain E0080`.
index 01a5e962c9491ea0d52cd89707f4c1d3c3ec4e74,0000000000000000000000000000000000000000..a22c6a5a0607d9ede572bdfd9ed7997237675717
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,55 @@@
 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of
 +           allow-dbg-in-tests
 +           allow-expect-in-tests
 +           allow-mixed-uninlined-format-args
 +           allow-print-in-tests
 +           allow-unwrap-in-tests
 +           allowed-scripts
 +           arithmetic-side-effects-allowed
++           arithmetic-side-effects-allowed-binary
++           arithmetic-side-effects-allowed-unary
 +           array-size-threshold
 +           avoid-breaking-exported-api
 +           await-holding-invalid-types
 +           blacklisted-names
 +           cargo-ignore-publish
 +           cognitive-complexity-threshold
 +           cyclomatic-complexity-threshold
 +           disallowed-macros
 +           disallowed-methods
 +           disallowed-names
 +           disallowed-types
 +           doc-valid-idents
 +           enable-raw-pointer-heuristic-for-send
 +           enforced-import-renames
 +           enum-variant-name-threshold
 +           enum-variant-size-threshold
 +           ignore-interior-mutability
 +           large-error-threshold
 +           literal-representation-threshold
 +           matches-for-let-else
 +           max-fn-params-bools
 +           max-include-file-size
 +           max-struct-bools
 +           max-suggested-slice-pattern-length
 +           max-trait-bounds
 +           msrv
 +           pass-by-value-size-limit
 +           single-char-binding-names-threshold
 +           standard-macro-braces
++           suppress-restriction-lint-in-const
 +           third-party
 +           too-large-for-stack
 +           too-many-arguments-threshold
 +           too-many-lines-threshold
 +           trivial-copy-size-limit
 +           type-complexity-threshold
 +           unreadable-literal-lint-fractions
 +           upper-case-acronyms-aggressive
 +           vec-box-size-threshold
 +           verbose-bit-mask-threshold
 +           warn-on-all-wildcard-imports
 +       at line 5 column 1
 +
 +error: aborting due to previous error
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6046addf719642fe62ca6bb87ae9d6896fdb00cb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,108 @@@
++// run-rustfix
++// edition:2018
++// aux-build:macro_rules.rs
++
++#![feature(exclusive_range_pattern)]
++#![feature(stmt_expr_attributes)]
++#![warn(clippy::almost_complete_range)]
++#![allow(ellipsis_inclusive_range_patterns)]
++#![allow(clippy::needless_parens_on_range_literals)]
++#![allow(clippy::double_parens)]
++
++#[macro_use]
++extern crate macro_rules;
++
++macro_rules! a {
++    () => {
++        'a'
++    };
++}
++macro_rules! A {
++    () => {
++        'A'
++    };
++}
++macro_rules! zero {
++    () => {
++        '0'
++    };
++}
++
++macro_rules! b {
++    () => {
++        let _ = 'a'..='z';
++        let _ = 'A'..='Z';
++        let _ = '0'..='9';
++    };
++}
++
++fn main() {
++    #[rustfmt::skip]
++    {
++        let _ = ('a') ..='z';
++        let _ = 'A' ..= ('Z');
++        let _ = ((('0'))) ..= ('9');
++    }
++
++    let _ = 'b'..'z';
++    let _ = 'B'..'Z';
++    let _ = '1'..'9';
++
++    let _ = (b'a')..=(b'z');
++    let _ = b'A'..=b'Z';
++    let _ = b'0'..=b'9';
++
++    let _ = b'b'..b'z';
++    let _ = b'B'..b'Z';
++    let _ = b'1'..b'9';
++
++    let _ = a!()..='z';
++    let _ = A!()..='Z';
++    let _ = zero!()..='9';
++
++    let _ = match 0u8 {
++        b'a'..=b'z' if true => 1,
++        b'A'..=b'Z' if true => 2,
++        b'0'..=b'9' if true => 3,
++        b'b'..b'z' => 4,
++        b'B'..b'Z' => 5,
++        b'1'..b'9' => 6,
++        _ => 7,
++    };
++
++    let _ = match 'x' {
++        'a'..='z' if true => 1,
++        'A'..='Z' if true => 2,
++        '0'..='9' if true => 3,
++        'b'..'z' => 4,
++        'B'..'Z' => 5,
++        '1'..'9' => 6,
++        _ => 7,
++    };
++
++    almost_complete_range!();
++    b!();
++}
++
++#[clippy::msrv = "1.25"]
++fn _under_msrv() {
++    let _ = match 'a' {
++        'a'...'z' => 1,
++        'A'...'Z' => 2,
++        '0'...'9' => 3,
++        _ => 4,
++    };
++}
++
++#[clippy::msrv = "1.26"]
++fn _meets_msrv() {
++    let _ = 'a'..='z';
++    let _ = 'A'..='Z';
++    let _ = '0'..='9';
++    let _ = match 'a' {
++        'a'..='z' => 1,
++        'A'..='Z' => 1,
++        '0'..='9' => 3,
++        _ => 4,
++    };
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ae7e07ab872b77f5e356f9711fad78115ea88b5b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,108 @@@
++// run-rustfix
++// edition:2018
++// aux-build:macro_rules.rs
++
++#![feature(exclusive_range_pattern)]
++#![feature(stmt_expr_attributes)]
++#![warn(clippy::almost_complete_range)]
++#![allow(ellipsis_inclusive_range_patterns)]
++#![allow(clippy::needless_parens_on_range_literals)]
++#![allow(clippy::double_parens)]
++
++#[macro_use]
++extern crate macro_rules;
++
++macro_rules! a {
++    () => {
++        'a'
++    };
++}
++macro_rules! A {
++    () => {
++        'A'
++    };
++}
++macro_rules! zero {
++    () => {
++        '0'
++    };
++}
++
++macro_rules! b {
++    () => {
++        let _ = 'a'..'z';
++        let _ = 'A'..'Z';
++        let _ = '0'..'9';
++    };
++}
++
++fn main() {
++    #[rustfmt::skip]
++    {
++        let _ = ('a') ..'z';
++        let _ = 'A' .. ('Z');
++        let _ = ((('0'))) .. ('9');
++    }
++
++    let _ = 'b'..'z';
++    let _ = 'B'..'Z';
++    let _ = '1'..'9';
++
++    let _ = (b'a')..(b'z');
++    let _ = b'A'..b'Z';
++    let _ = b'0'..b'9';
++
++    let _ = b'b'..b'z';
++    let _ = b'B'..b'Z';
++    let _ = b'1'..b'9';
++
++    let _ = a!()..'z';
++    let _ = A!()..'Z';
++    let _ = zero!()..'9';
++
++    let _ = match 0u8 {
++        b'a'..b'z' if true => 1,
++        b'A'..b'Z' if true => 2,
++        b'0'..b'9' if true => 3,
++        b'b'..b'z' => 4,
++        b'B'..b'Z' => 5,
++        b'1'..b'9' => 6,
++        _ => 7,
++    };
++
++    let _ = match 'x' {
++        'a'..'z' if true => 1,
++        'A'..'Z' if true => 2,
++        '0'..'9' if true => 3,
++        'b'..'z' => 4,
++        'B'..'Z' => 5,
++        '1'..'9' => 6,
++        _ => 7,
++    };
++
++    almost_complete_range!();
++    b!();
++}
++
++#[clippy::msrv = "1.25"]
++fn _under_msrv() {
++    let _ = match 'a' {
++        'a'..'z' => 1,
++        'A'..'Z' => 2,
++        '0'..'9' => 3,
++        _ => 4,
++    };
++}
++
++#[clippy::msrv = "1.26"]
++fn _meets_msrv() {
++    let _ = 'a'..'z';
++    let _ = 'A'..'Z';
++    let _ = '0'..'9';
++    let _ = match 'a' {
++        'a'..'z' => 1,
++        'A'..'Z' => 1,
++        '0'..'9' => 3,
++        _ => 4,
++    };
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a7a5328785025f6945e361d207fff35c027c5841
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,235 @@@
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:42:17
++   |
++LL |         let _ = ('a') ..'z';
++   |                 ^^^^^^--^^^
++   |                       |
++   |                       help: use an inclusive range: `..=`
++   |
++   = note: `-D clippy::almost-complete-range` implied by `-D warnings`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:43:17
++   |
++LL |         let _ = 'A' .. ('Z');
++   |                 ^^^^--^^^^^^
++   |                     |
++   |                     help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:44:17
++   |
++LL |         let _ = ((('0'))) .. ('9');
++   |                 ^^^^^^^^^^--^^^^^^
++   |                           |
++   |                           help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:51:13
++   |
++LL |     let _ = (b'a')..(b'z');
++   |             ^^^^^^--^^^^^^
++   |                   |
++   |                   help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:52:13
++   |
++LL |     let _ = b'A'..b'Z';
++   |             ^^^^--^^^^
++   |                 |
++   |                 help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:53:13
++   |
++LL |     let _ = b'0'..b'9';
++   |             ^^^^--^^^^
++   |                 |
++   |                 help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:59:13
++   |
++LL |     let _ = a!()..'z';
++   |             ^^^^--^^^
++   |                 |
++   |                 help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:60:13
++   |
++LL |     let _ = A!()..'Z';
++   |             ^^^^--^^^
++   |                 |
++   |                 help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:61:13
++   |
++LL |     let _ = zero!()..'9';
++   |             ^^^^^^^--^^^
++   |                    |
++   |                    help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:64:9
++   |
++LL |         b'a'..b'z' if true => 1,
++   |         ^^^^--^^^^
++   |             |
++   |             help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:65:9
++   |
++LL |         b'A'..b'Z' if true => 2,
++   |         ^^^^--^^^^
++   |             |
++   |             help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:66:9
++   |
++LL |         b'0'..b'9' if true => 3,
++   |         ^^^^--^^^^
++   |             |
++   |             help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:74:9
++   |
++LL |         'a'..'z' if true => 1,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:75:9
++   |
++LL |         'A'..'Z' if true => 2,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:76:9
++   |
++LL |         '0'..'9' if true => 3,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:33:17
++   |
++LL |         let _ = 'a'..'z';
++   |                 ^^^--^^^
++   |                    |
++   |                    help: use an inclusive range: `..=`
++...
++LL |     b!();
++   |     ---- in this macro invocation
++   |
++   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:34:17
++   |
++LL |         let _ = 'A'..'Z';
++   |                 ^^^--^^^
++   |                    |
++   |                    help: use an inclusive range: `..=`
++...
++LL |     b!();
++   |     ---- in this macro invocation
++   |
++   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:35:17
++   |
++LL |         let _ = '0'..'9';
++   |                 ^^^--^^^
++   |                    |
++   |                    help: use an inclusive range: `..=`
++...
++LL |     b!();
++   |     ---- in this macro invocation
++   |
++   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:90:9
++   |
++LL |         'a'..'z' => 1,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `...`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:91:9
++   |
++LL |         'A'..'Z' => 2,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `...`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:92:9
++   |
++LL |         '0'..'9' => 3,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `...`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:99:13
++   |
++LL |     let _ = 'a'..'z';
++   |             ^^^--^^^
++   |                |
++   |                help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:100:13
++   |
++LL |     let _ = 'A'..'Z';
++   |             ^^^--^^^
++   |                |
++   |                help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:101:13
++   |
++LL |     let _ = '0'..'9';
++   |             ^^^--^^^
++   |                |
++   |                help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:103:9
++   |
++LL |         'a'..'z' => 1,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:104:9
++   |
++LL |         'A'..'Z' => 1,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: almost complete ascii range
++  --> $DIR/almost_complete_range.rs:105:9
++   |
++LL |         '0'..'9' => 3,
++   |         ^^^--^^^
++   |            |
++   |            help: use an inclusive range: `..=`
++
++error: aborting due to 27 previous errors
++
index 0259a0824e794cc7ba5a0f957f0130f6b3c49a0e,0000000000000000000000000000000000000000..9fe4b7cf28d8d3fc4ee574fa194d060adc6f3d8f
mode 100644,000000..100644
--- /dev/null
@@@ -1,352 -1,0 +1,334 @@@
- error: arithmetic operation that can potentially result in unexpected side-effects
-   --> $DIR/arithmetic_side_effects.rs:78:13
-    |
- LL |     let _ = String::new() + "";
-    |             ^^^^^^^^^^^^^^^^^^
-    |
-    = 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:86:27
-    |
- LL |     let inferred_string = string + "";
-    |                           ^^^^^^^^^^^
- error: arithmetic operation that can potentially result in unexpected side-effects
-   --> $DIR/arithmetic_side_effects.rs:90:13
-    |
- LL |     let _ = inferred_string + "";
-    |             ^^^^^^^^^^^^^^^^^^^^
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:165:5
 +   |
 +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:166:5
 +   |
 +LL |     _n += &1;
 +   |     ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:167:5
 +   |
 +LL |     _n -= 1;
 +   |     ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:168:5
 +   |
 +LL |     _n -= &1;
 +   |     ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:169:5
 +   |
 +LL |     _n /= 0;
 +   |     ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:170:5
 +   |
 +LL |     _n /= &0;
 +   |     ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:171:5
 +   |
 +LL |     _n %= 0;
 +   |     ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:172:5
 +   |
 +LL |     _n %= &0;
 +   |     ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:173:5
 +   |
 +LL |     _n *= 2;
 +   |     ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:174:5
 +   |
 +LL |     _n *= &2;
 +   |     ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:177:10
 +   |
 +LL |     _n = _n + 1;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:178:10
 +   |
 +LL |     _n = _n + &1;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:179:10
 +   |
 +LL |     _n = 1 + _n;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:180:10
 +   |
 +LL |     _n = &1 + _n;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:181:10
 +   |
 +LL |     _n = _n - 1;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:182:10
 +   |
 +LL |     _n = _n - &1;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:183:10
 +   |
 +LL |     _n = 1 - _n;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:184:10
 +   |
 +LL |     _n = &1 - _n;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:185:10
 +   |
 +LL |     _n = _n / 0;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:186:10
 +   |
 +LL |     _n = _n / &0;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:187:10
 +   |
 +LL |     _n = _n % 0;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:188:10
 +   |
 +LL |     _n = _n % &0;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:189:10
 +   |
 +LL |     _n = _n * 2;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:190:10
 +   |
 +LL |     _n = _n * &2;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:191:10
 +   |
 +LL |     _n = 2 * _n;
 +   |          ^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:192:10
 +   |
 +LL |     _n = &2 * _n;
 +   |          ^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:193:10
 +   |
 +LL |     _n = 23 + &85;
 +   |          ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:194:10
 +   |
 +LL |     _n = &23 + 85;
 +   |          ^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:195:10
 +   |
 +LL |     _n = &23 + &85;
 +   |          ^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:198:13
 +   |
 +LL |     let _ = Custom + 0;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:199:13
 +   |
 +LL |     let _ = Custom + 1;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:200:13
 +   |
 +LL |     let _ = Custom + 2;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:201:13
 +   |
 +LL |     let _ = Custom + 0.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:202:13
 +   |
 +LL |     let _ = Custom + 1.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:203:13
 +   |
 +LL |     let _ = Custom + 2.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:204:13
 +   |
 +LL |     let _ = Custom - 0;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:205:13
 +   |
 +LL |     let _ = Custom - 1;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:206:13
 +   |
 +LL |     let _ = Custom - 2;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:207:13
 +   |
 +LL |     let _ = Custom - 0.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:208:13
 +   |
 +LL |     let _ = Custom - 1.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:209:13
 +   |
 +LL |     let _ = Custom - 2.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:210:13
 +   |
 +LL |     let _ = Custom / 0;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:211:13
 +   |
 +LL |     let _ = Custom / 1;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:212:13
 +   |
 +LL |     let _ = Custom / 2;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:213:13
 +   |
 +LL |     let _ = Custom / 0.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:214:13
 +   |
 +LL |     let _ = Custom / 1.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:215:13
 +   |
 +LL |     let _ = Custom / 2.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:216:13
 +   |
 +LL |     let _ = Custom * 0;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:217:13
 +   |
 +LL |     let _ = Custom * 1;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:218:13
 +   |
 +LL |     let _ = Custom * 2;
 +   |             ^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:219:13
 +   |
 +LL |     let _ = Custom * 0.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:220:13
 +   |
 +LL |     let _ = Custom * 1.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:221:13
 +   |
 +LL |     let _ = Custom * 2.0;
 +   |             ^^^^^^^^^^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:224:10
 +   |
 +LL |     _n = -_n;
 +   |          ^^^
 +
 +error: arithmetic operation that can potentially result in unexpected side-effects
 +  --> $DIR/arithmetic_side_effects.rs:225:10
 +   |
 +LL |     _n = -&_n;
 +   |          ^^^^
 +
- error: aborting due to 58 previous errors
++error: aborting due to 55 previous errors
 +
index ef3ca9aea380c0bfba020deffb65b601f56a90b4,0000000000000000000000000000000000000000..1e5f20e8c39baf5ad8c47d5dd77530bfcba75dc6
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,151 @@@
- macro_rules! almost_complete_letter_range {
 +#![allow(dead_code)]
 +
 +//! Used to test that certain lints don't trigger in imported external macros
 +
 +#[macro_export]
 +macro_rules! foofoo {
 +    () => {
 +        loop {}
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! must_use_unit {
 +    () => {
 +        #[must_use]
 +        fn foo() {}
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! try_err {
 +    () => {
 +        pub fn try_err_fn() -> Result<i32, i32> {
 +            let err: i32 = 1;
 +            // To avoid warnings during rustfix
 +            if true { Err(err)? } else { Ok(2) }
 +        }
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! string_add {
 +    () => {
 +        let y = "".to_owned();
 +        let z = y + "...";
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! take_external {
 +    ($s:expr) => {
 +        std::mem::replace($s, Default::default())
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! option_env_unwrap_external {
 +    ($env: expr) => {
 +        option_env!($env).unwrap()
 +    };
 +    ($env: expr, $message: expr) => {
 +        option_env!($env).expect($message)
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! ref_arg_binding {
 +    () => {
 +        let ref _y = 42;
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! ref_arg_function {
 +    () => {
 +        fn fun_example(ref _x: usize) {}
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! as_conv_with_arg {
 +    (0u32 as u64) => {
 +        ()
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! as_conv {
 +    () => {
 +        0u32 as u64
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! large_enum_variant {
 +    () => {
 +        enum LargeEnumInMacro {
 +            A(i32),
 +            B([i32; 8000]),
 +        }
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! field_reassign_with_default {
 +    () => {
 +        #[derive(Default)]
 +        struct A {
 +            pub i: i32,
 +            pub j: i64,
 +        }
 +        fn lint() {
 +            let mut a: A = Default::default();
 +            a.i = 42;
 +            a;
 +        }
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! default_numeric_fallback {
 +    () => {
 +        let x = 22;
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! mut_mut {
 +    () => {
 +        let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! ptr_as_ptr_cast {
 +    ($ptr: ident) => {
 +        $ptr as *const i32
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! manual_rem_euclid {
 +    () => {
 +        let value: i32 = 5;
 +        let _: i32 = ((value % 4) + 4) % 4;
 +    };
 +}
 +
 +#[macro_export]
 +macro_rules! equatable_if_let {
 +    ($a:ident) => {{ if let 2 = $a {} }};
 +}
 +
 +#[macro_export]
++macro_rules! almost_complete_range {
 +    () => {
 +        let _ = 'a'..'z';
++        let _ = 'A'..'Z';
++        let _ = '0'..'9';
 +    };
 +}
index 72a708b40737b3932688127ec9b1905901bacb86,0000000000000000000000000000000000000000..925cbf25368fbd18b3ceb6b537b38070e82266a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,53 @@@
 +// run-rustfix
 +
 +#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 +#![warn(clippy::cast_lossless)]
 +
 +fn main() {
 +    // Test clippy::cast_lossless with casts to integer types
 +    let _ = i16::from(1i8);
 +    let _ = i32::from(1i8);
 +    let _ = i64::from(1i8);
 +    let _ = i16::from(1u8);
 +    let _ = i32::from(1u8);
 +    let _ = i64::from(1u8);
 +    let _ = u16::from(1u8);
 +    let _ = u32::from(1u8);
 +    let _ = u64::from(1u8);
 +    let _ = i32::from(1i16);
 +    let _ = i64::from(1i16);
 +    let _ = i32::from(1u16);
 +    let _ = i64::from(1u16);
 +    let _ = u32::from(1u16);
 +    let _ = u64::from(1u16);
 +    let _ = i64::from(1i32);
 +    let _ = i64::from(1u32);
 +    let _ = u64::from(1u32);
 +
 +    // Test with an expression wrapped in parens
 +    let _ = u16::from(1u8 + 1u8);
 +}
 +
 +// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
 +// so we skip the lint if the expression is in a const fn.
 +// See #3656
 +const fn abc(input: u16) -> u32 {
 +    input as u32
 +}
 +
 +// Same as the above issue. We can't suggest `::from` in const fns in impls
 +mod cast_lossless_in_impl {
 +    struct A;
 +
 +    impl A {
 +        pub const fn convert(x: u32) -> u64 {
 +            x as u64
 +        }
 +    }
 +}
++
++#[derive(PartialEq, Debug)]
++#[repr(i64)]
++enum Test {
++    A = u32::MAX as i64 + 1,
++}
index 34bb47181e69deffcf1bfe283ed4557b68d08c4e,0000000000000000000000000000000000000000..c82bd9108d23bfb8ad03bc97911c76d49e00cb67
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,53 @@@
 +// run-rustfix
 +
 +#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 +#![warn(clippy::cast_lossless)]
 +
 +fn main() {
 +    // Test clippy::cast_lossless with casts to integer types
 +    let _ = 1i8 as i16;
 +    let _ = 1i8 as i32;
 +    let _ = 1i8 as i64;
 +    let _ = 1u8 as i16;
 +    let _ = 1u8 as i32;
 +    let _ = 1u8 as i64;
 +    let _ = 1u8 as u16;
 +    let _ = 1u8 as u32;
 +    let _ = 1u8 as u64;
 +    let _ = 1i16 as i32;
 +    let _ = 1i16 as i64;
 +    let _ = 1u16 as i32;
 +    let _ = 1u16 as i64;
 +    let _ = 1u16 as u32;
 +    let _ = 1u16 as u64;
 +    let _ = 1i32 as i64;
 +    let _ = 1u32 as i64;
 +    let _ = 1u32 as u64;
 +
 +    // Test with an expression wrapped in parens
 +    let _ = (1u8 + 1u8) as u16;
 +}
 +
 +// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
 +// so we skip the lint if the expression is in a const fn.
 +// See #3656
 +const fn abc(input: u16) -> u32 {
 +    input as u32
 +}
 +
 +// Same as the above issue. We can't suggest `::from` in const fns in impls
 +mod cast_lossless_in_impl {
 +    struct A;
 +
 +    impl A {
 +        pub const fn convert(x: u32) -> u64 {
 +            x as u64
 +        }
 +    }
 +}
++
++#[derive(PartialEq, Debug)]
++#[repr(i64)]
++enum Test {
++    A = u32::MAX as i64 + 1,
++}
index 49fc9a9629e25415a714b6e3616602c77367f239,0000000000000000000000000000000000000000..9792ae9ed6b8b34ddb097b3c17be2cf15a4692f4
mode 100644,000000..100644
--- /dev/null
@@@ -1,73 -1,0 +1,84 @@@
 +// run-rustfix
 +
++#![allow(unused)]
 +#![warn(clippy::collapsible_str_replace)]
 +
 +fn get_filter() -> char {
 +    'u'
 +}
 +
 +fn main() {
 +    let d = 'd';
 +    let p = 'p';
 +    let s = 's';
 +    let u = 'u';
 +    let l = "l";
 +
 +    let mut iter = ["l", "z"].iter();
 +
 +    // LINT CASES
 +    let _ = "hesuo worpd".replace(['s', 'u'], "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u'], l);
 +
 +    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l");
 +
 +    let _ = "hesuo worpd"
 +        .replace(['s', 'u', 'p', 'd'], "l");
 +
 +    let _ = "hesuo world".replace([s, 'u'], "l");
 +
 +    let _ = "hesuo worpd".replace([s, 'u', 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace([s, u, 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace([s, u, p], "l");
 +
 +    let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d");
 +
 +    let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l");
 +
 +    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
 +    let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l");
 +
 +    let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l");
 +
 +    let _ = "hesuo world".replace([get_filter(), 's'], "l");
 +
 +    // NO LINT CASES
 +    let _ = "hesuo world".replace('s', "l").replace('u', "p");
 +
 +    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
 +
 +    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
 +
 +    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
 +    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
 +
 +    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
 +
 +    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
 +
 +    // Regression test
 +    let _ = "hesuo worpd"
 +        .replace('u', iter.next().unwrap())
 +        .replace('s', iter.next().unwrap());
 +}
++
++#[clippy::msrv = "1.57"]
++fn msrv_1_57() {
++    let _ = "".replace('a', "1.57").replace('b', "1.57");
++}
++
++#[clippy::msrv = "1.58"]
++fn msrv_1_58() {
++    let _ = "".replace(['a', 'b'], "1.58");
++}
index e3e25c4146ffa6bdd7a71bcd2067ba9a6ec6b68e,0000000000000000000000000000000000000000..baee185b79ea388e77b8d143de03d68d92c964a9
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,87 @@@
 +// run-rustfix
 +
++#![allow(unused)]
 +#![warn(clippy::collapsible_str_replace)]
 +
 +fn get_filter() -> char {
 +    'u'
 +}
 +
 +fn main() {
 +    let d = 'd';
 +    let p = 'p';
 +    let s = 's';
 +    let u = 'u';
 +    let l = "l";
 +
 +    let mut iter = ["l", "z"].iter();
 +
 +    // LINT CASES
 +    let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
 +
 +    let _ = "hesuo worpd".replace('s', l).replace('u', l);
 +
 +    let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
 +
 +    let _ = "hesuo worpd"
 +        .replace('s', "l")
 +        .replace('u', "l")
 +        .replace('p', "l")
 +        .replace('d', "l");
 +
 +    let _ = "hesuo world".replace(s, "l").replace('u', "l");
 +
 +    let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
 +
 +    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
 +
 +    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
 +
 +    let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
 +
 +    let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
 +
 +    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
 +    let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
 +
 +    let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
 +
 +    let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
 +
 +    // NO LINT CASES
 +    let _ = "hesuo world".replace('s', "l").replace('u', "p");
 +
 +    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
 +
 +    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
 +
 +    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
 +    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
 +
 +    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
 +
 +    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
 +
 +    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
 +
 +    // Regression test
 +    let _ = "hesuo worpd"
 +        .replace('u', iter.next().unwrap())
 +        .replace('s', iter.next().unwrap());
 +}
++
++#[clippy::msrv = "1.57"]
++fn msrv_1_57() {
++    let _ = "".replace('a', "1.57").replace('b', "1.57");
++}
++
++#[clippy::msrv = "1.58"]
++fn msrv_1_58() {
++    let _ = "".replace('a', "1.58").replace('b', "1.58");
++}
index 8e3daf3b898a3328e6f5f9de77f42e24f2729b79,0000000000000000000000000000000000000000..223358cf53f3e0e07c8b2db2c37a9d4cb9f619b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,86 -1,0 +1,92 @@@
-   --> $DIR/collapsible_str_replace.rs:19:27
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:21:27
++  --> $DIR/collapsible_str_replace.rs:20:27
 +   |
 +LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
 +   |
 +   = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:23:27
++  --> $DIR/collapsible_str_replace.rs:22:27
 +   |
 +LL |     let _ = "hesuo worpd".replace('s', l).replace('u', l);
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:26:10
++  --> $DIR/collapsible_str_replace.rs:24:27
 +   |
 +LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:31:27
++  --> $DIR/collapsible_str_replace.rs:27:10
 +   |
 +LL |           .replace('s', "l")
 +   |  __________^
 +LL | |         .replace('u', "l")
 +LL | |         .replace('p', "l")
 +LL | |         .replace('d', "l");
 +   | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:33:27
++  --> $DIR/collapsible_str_replace.rs:32:27
 +   |
 +LL |     let _ = "hesuo world".replace(s, "l").replace('u', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:35:27
++  --> $DIR/collapsible_str_replace.rs:34:27
 +   |
 +LL |     let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:37:27
++  --> $DIR/collapsible_str_replace.rs:36:27
 +   |
 +LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:39:27
++  --> $DIR/collapsible_str_replace.rs:38:27
 +   |
 +LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:41:45
++  --> $DIR/collapsible_str_replace.rs:40:27
 +   |
 +LL |     let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:44:47
++  --> $DIR/collapsible_str_replace.rs:42:45
 +   |
 +LL |     let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
 +   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:46:28
++  --> $DIR/collapsible_str_replace.rs:45:47
 +   |
 +LL |     let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
 +   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
-   --> $DIR/collapsible_str_replace.rs:48:27
++  --> $DIR/collapsible_str_replace.rs:47:28
 +   |
 +LL |     let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
 +
 +error: used consecutive `str::replace` call
- error: aborting due to 13 previous errors
++  --> $DIR/collapsible_str_replace.rs:49:27
 +   |
 +LL |     let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
 +
++error: used consecutive `str::replace` call
++  --> $DIR/collapsible_str_replace.rs:86:16
++   |
++LL |     let _ = "".replace('a', "1.58").replace('b', "1.58");
++   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")`
++
++error: aborting due to 14 previous errors
 +
index 6eddc01e2c471215af0fa4584f5083e5a1eec796,0000000000000000000000000000000000000000..46565a97f005979b3bc03a5a4555d41a8c2ac0cc
mode 100644,000000..100644
--- /dev/null
@@@ -1,191 -1,0 +1,221 @@@
 +#![warn(clippy::explicit_counter_loop)]
 +#![allow(clippy::uninlined_format_args)]
 +
 +fn main() {
 +    let mut vec = vec![1, 2, 3, 4];
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 1;
 +    _index = 0;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &mut vec {
 +        _index += 1;
 +    }
 +
 +    let mut _index = 0;
 +    for _v in vec {
 +        _index += 1;
 +    }
 +}
 +
 +mod issue_1219 {
 +    pub fn test() {
 +        // should not trigger the lint because variable is used after the loop #473
 +        let vec = vec![1, 2, 3];
 +        let mut index = 0;
 +        for _v in &vec {
 +            index += 1
 +        }
 +        println!("index: {}", index);
 +
 +        // should not trigger the lint because the count is conditional #1219
 +        let text = "banana";
 +        let mut count = 0;
 +        for ch in text.chars() {
 +            println!("{}", count);
 +            if ch == 'a' {
 +                continue;
 +            }
 +            count += 1;
 +        }
 +
 +        // should not trigger the lint because the count is conditional
 +        let text = "banana";
 +        let mut count = 0;
 +        for ch in text.chars() {
 +            println!("{}", count);
 +            if ch == 'a' {
 +                count += 1;
 +            }
 +        }
 +
 +        // should trigger the lint because the count is not conditional
 +        let text = "banana";
 +        let mut count = 0;
 +        for ch in text.chars() {
 +            println!("{}", count);
 +            count += 1;
 +            if ch == 'a' {
 +                continue;
 +            }
 +        }
 +
 +        // should trigger the lint because the count is not conditional
 +        let text = "banana";
 +        let mut count = 0;
 +        for ch in text.chars() {
 +            println!("{}", count);
 +            count += 1;
 +            for i in 0..2 {
 +                let _ = 123;
 +            }
 +        }
 +
 +        // should not trigger the lint because the count is incremented multiple times
 +        let text = "banana";
 +        let mut count = 0;
 +        for ch in text.chars() {
 +            println!("{}", count);
 +            count += 1;
 +            for i in 0..2 {
 +                count += 1;
 +            }
 +        }
 +    }
 +}
 +
 +mod issue_3308 {
 +    pub fn test() {
 +        // should not trigger the lint because the count is incremented multiple times
 +        let mut skips = 0;
 +        let erasures = vec![];
 +        for i in 0..10 {
 +            println!("{}", skips);
 +            while erasures.contains(&(i + skips)) {
 +                skips += 1;
 +            }
 +        }
 +
 +        // should not trigger the lint because the count is incremented multiple times
 +        let mut skips = 0;
 +        for i in 0..10 {
 +            println!("{}", skips);
 +            let mut j = 0;
 +            while j < 5 {
 +                skips += 1;
 +                j += 1;
 +            }
 +        }
 +
 +        // should not trigger the lint because the count is incremented multiple times
 +        let mut skips = 0;
 +        for i in 0..10 {
 +            println!("{}", skips);
 +            for j in 0..5 {
 +                skips += 1;
 +            }
 +        }
 +    }
 +}
 +
 +mod issue_1670 {
 +    pub fn test() {
 +        let mut count = 0;
 +        for _i in 3..10 {
 +            count += 1;
 +        }
 +    }
 +}
 +
 +mod issue_4732 {
 +    pub fn test() {
 +        let slice = &[1, 2, 3];
 +        let mut index = 0;
 +
 +        // should not trigger the lint because the count is used after the loop
 +        for _v in slice {
 +            index += 1
 +        }
 +        let _closure = || println!("index: {}", index);
 +    }
 +}
 +
 +mod issue_4677 {
 +    pub fn test() {
 +        let slice = &[1, 2, 3];
 +
 +        // should not trigger the lint because the count is used after incremented
 +        let mut count = 0;
 +        for _i in slice {
 +            count += 1;
 +            println!("{}", count);
 +        }
 +    }
 +}
 +
 +mod issue_7920 {
 +    pub fn test() {
 +        let slice = &[1, 2, 3];
 +
 +        let index_usize: usize = 0;
 +        let mut idx_usize: usize = 0;
 +
 +        // should suggest `enumerate`
 +        for _item in slice {
 +            if idx_usize == index_usize {
 +                break;
 +            }
 +
 +            idx_usize += 1;
 +        }
 +
 +        let index_u32: u32 = 0;
 +        let mut idx_u32: u32 = 0;
 +
 +        // should suggest `zip`
 +        for _item in slice {
 +            if idx_u32 == index_u32 {
 +                break;
 +            }
 +
 +            idx_u32 += 1;
 +        }
 +    }
 +}
++
++mod issue_10058 {
++    pub fn test() {
++        // should not lint since we are increasing counter potentially more than once in the loop
++        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
++        let mut counter = 0;
++        for value in values {
++            counter += 1;
++
++            if value == 0 {
++                continue;
++            }
++
++            counter += 1;
++        }
++    }
++
++    pub fn test2() {
++        // should not lint since we are increasing counter potentially more than once in the loop
++        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
++        let mut counter = 0;
++        for value in values {
++            counter += 1;
++
++            if value != 0 {
++                counter += 1;
++            }
++        }
++    }
++}
index 125c9a69cd3fd1fdd48f8b7a37d7672d84f18a9a,0000000000000000000000000000000000000000..72d635c2ccd65609ada5efc15d5197457ec4b622
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,91 @@@
 +// run-rustfix
 +
++#![feature(type_alias_impl_trait)]
 +#![warn(clippy::from_over_into)]
 +#![allow(unused)]
 +
 +// this should throw an error
 +struct StringWrapper(String);
 +
 +impl From<String> for StringWrapper {
 +    fn from(val: String) -> Self {
 +        StringWrapper(val)
 +    }
 +}
 +
 +struct SelfType(String);
 +
 +impl From<String> for SelfType {
 +    fn from(val: String) -> Self {
 +        SelfType(String::new())
 +    }
 +}
 +
 +#[derive(Default)]
 +struct X;
 +
 +impl X {
 +    const FOO: &'static str = "a";
 +}
 +
 +struct SelfKeywords;
 +
 +impl From<X> for SelfKeywords {
 +    fn from(val: X) -> Self {
 +        let _ = X::default();
 +        let _ = X::FOO;
 +        let _: X = val;
 +
 +        SelfKeywords
 +    }
 +}
 +
 +struct ExplicitPaths(bool);
 +
 +impl core::convert::From<crate::ExplicitPaths> for bool {
 +    fn from(mut val: crate::ExplicitPaths) -> Self {
 +        let in_closure = || val.0;
 +
 +        val.0 = false;
 +        val.0
 +    }
 +}
 +
 +// this is fine
 +struct A(String);
 +
 +impl From<String> for A {
 +    fn from(s: String) -> A {
 +        A(s)
 +    }
 +}
 +
 +#[clippy::msrv = "1.40"]
 +fn msrv_1_40() {
 +    struct FromOverInto<T>(Vec<T>);
 +
 +    impl<T> Into<FromOverInto<T>> for Vec<T> {
 +        fn into(self) -> FromOverInto<T> {
 +            FromOverInto(self)
 +        }
 +    }
 +}
 +
 +#[clippy::msrv = "1.41"]
 +fn msrv_1_41() {
 +    struct FromOverInto<T>(Vec<T>);
 +
 +    impl<T> From<Vec<T>> for FromOverInto<T> {
 +        fn from(val: Vec<T>) -> Self {
 +            FromOverInto(val)
 +        }
 +    }
 +}
 +
++type Opaque = impl Sized;
++struct IntoOpaque;
++impl Into<Opaque> for IntoOpaque {
++    fn into(self) -> Opaque {}
++}
++
 +fn main() {}
index 5aa127bfabe4b792a59ab914277c7034d7e06b2b,0000000000000000000000000000000000000000..965f4d5d7859ee47484ccc12da79112bbc743fad
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,91 @@@
 +// run-rustfix
 +
++#![feature(type_alias_impl_trait)]
 +#![warn(clippy::from_over_into)]
 +#![allow(unused)]
 +
 +// this should throw an error
 +struct StringWrapper(String);
 +
 +impl Into<StringWrapper> for String {
 +    fn into(self) -> StringWrapper {
 +        StringWrapper(self)
 +    }
 +}
 +
 +struct SelfType(String);
 +
 +impl Into<SelfType> for String {
 +    fn into(self) -> SelfType {
 +        SelfType(Self::new())
 +    }
 +}
 +
 +#[derive(Default)]
 +struct X;
 +
 +impl X {
 +    const FOO: &'static str = "a";
 +}
 +
 +struct SelfKeywords;
 +
 +impl Into<SelfKeywords> for X {
 +    fn into(self) -> SelfKeywords {
 +        let _ = Self::default();
 +        let _ = Self::FOO;
 +        let _: Self = self;
 +
 +        SelfKeywords
 +    }
 +}
 +
 +struct ExplicitPaths(bool);
 +
 +impl core::convert::Into<bool> for crate::ExplicitPaths {
 +    fn into(mut self) -> bool {
 +        let in_closure = || self.0;
 +
 +        self.0 = false;
 +        self.0
 +    }
 +}
 +
 +// this is fine
 +struct A(String);
 +
 +impl From<String> for A {
 +    fn from(s: String) -> A {
 +        A(s)
 +    }
 +}
 +
 +#[clippy::msrv = "1.40"]
 +fn msrv_1_40() {
 +    struct FromOverInto<T>(Vec<T>);
 +
 +    impl<T> Into<FromOverInto<T>> for Vec<T> {
 +        fn into(self) -> FromOverInto<T> {
 +            FromOverInto(self)
 +        }
 +    }
 +}
 +
 +#[clippy::msrv = "1.41"]
 +fn msrv_1_41() {
 +    struct FromOverInto<T>(Vec<T>);
 +
 +    impl<T> Into<FromOverInto<T>> for Vec<T> {
 +        fn into(self) -> FromOverInto<T> {
 +            FromOverInto(self)
 +        }
 +    }
 +}
 +
++type Opaque = impl Sized;
++struct IntoOpaque;
++impl Into<Opaque> for IntoOpaque {
++    fn into(self) -> Opaque {}
++}
++
 +fn main() {}
index a1764a5ea12ae8f5deef37156c803d244523c4f0,0000000000000000000000000000000000000000..3c4d011d6fb468e735fb07c7d49a7064bad3fcc7
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
-   --> $DIR/from_over_into.rs:9:1
 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-   --> $DIR/from_over_into.rs:17:1
++  --> $DIR/from_over_into.rs:10:1
 +   |
 +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>`
 +   |
 +LL ~ impl From<String> for StringWrapper {
 +LL ~     fn from(val: String) -> Self {
 +LL ~         StringWrapper(val)
 +   |
 +
 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-   --> $DIR/from_over_into.rs:32:1
++  --> $DIR/from_over_into.rs:18:1
 +   |
 +LL | impl Into<SelfType> for String {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: replace the `Into` implentation with `From<std::string::String>`
 +   |
 +LL ~ impl From<String> for SelfType {
 +LL ~     fn from(val: String) -> Self {
 +LL ~         SelfType(String::new())
 +   |
 +
 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-   --> $DIR/from_over_into.rs:44:1
++  --> $DIR/from_over_into.rs:33:1
 +   |
 +LL | impl Into<SelfKeywords> for X {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: replace the `Into` implentation with `From<X>`
 +   |
 +LL ~ impl From<X> for SelfKeywords {
 +LL ~     fn from(val: X) -> Self {
 +LL ~         let _ = X::default();
 +LL ~         let _ = X::FOO;
 +LL ~         let _: X = val;
 +   |
 +
 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-   --> $DIR/from_over_into.rs:77:5
++  --> $DIR/from_over_into.rs:45:1
 +   |
 +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>`
 +   |
 +LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
 +LL ~     fn from(mut val: crate::ExplicitPaths) -> Self {
 +LL ~         let in_closure = || val.0;
 +LL | 
 +LL ~         val.0 = false;
 +LL ~         val.0
 +   |
 +
 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
++  --> $DIR/from_over_into.rs:78:5
 +   |
 +LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
 +   |
 +LL ~     impl<T> From<Vec<T>> for FromOverInto<T> {
 +LL ~         fn from(val: Vec<T>) -> Self {
 +LL ~             FromOverInto(val)
 +   |
 +
 +error: aborting due to 5 previous errors
 +
index e7b9a78c5dbc3e3fdf95f0aa971f8c128b672e23,0000000000000000000000000000000000000000..cac69ef42c4136e36e5b8571b0963c62b799b11a
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,123 @@@
-     &x;
 +// run-rustfix
 +#![warn(clippy::identity_op)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::eq_op,
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::op_ref,
 +    clippy::double_parens,
 +    clippy::uninlined_format_args
 +)]
 +
 +use std::fmt::Write as _;
 +
 +const ONE: i64 = 1;
 +const NEG_ONE: i64 = -1;
 +const ZERO: i64 = 0;
 +
 +struct A(String);
 +
 +impl std::ops::Shl<i32> for A {
 +    type Output = A;
 +    fn shl(mut self, other: i32) -> Self {
 +        let _ = write!(self.0, "{}", other);
 +        self
 +    }
 +}
 +
 +struct Length(u8);
 +struct Meter;
 +
 +impl core::ops::Mul<Meter> for u8 {
 +    type Output = Length;
 +    fn mul(self, _: Meter) -> Length {
 +        Length(self)
 +    }
 +}
 +
 +#[rustfmt::skip]
 +fn main() {
 +    let x = 0;
 +
 +    x;
 +    x;
 +    x + 1;
 +    x;
 +    1 + x;
 +    x - ZERO; //no error, as we skip lookups (for now)
 +    x;
 +    ((ZERO)) | x; //no error, as we skip lookups (for now)
 +
 +    x;
 +    x;
 +    x / ONE; //no error, as we skip lookups (for now)
 +
 +    x / 2; //no false positive
 +
 +    x & NEG_ONE; //no error, as we skip lookups (for now)
 +    x;
 +
 +    let u: u8 = 0;
 +    u;
 +
 +    1 << 0; // no error, this case is allowed, see issue 3430
 +    42;
 +    1;
 +    42;
++    x;
 +    x;
 +
 +    let mut a = A(String::new());
 +    let b = a << 0; // no error: non-integer
 +
 +    1 * Meter; // no error: non-integer
 +
 +    2;
 +    -2;
 +    2 + x;
 +    -2 + x;
 +    x + 1;
 +    (x + 1) % 3; // no error
 +    4 % 3; // no error
 +    4 % -3; // no error
 +
 +    // See #8724
 +    let a = 0;
 +    let b = true;
 +    (if b { 1 } else { 2 });
 +    (if b { 1 } else { 2 }) + if b { 3 } else { 4 };
 +    (match a { 0 => 10, _ => 20 });
 +    (match a { 0 => 10, _ => 20 }) + match a { 0 => 30, _ => 40 };
 +    (if b { 1 } else { 2 }) + match a { 0 => 30, _ => 40 };
 +    (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
 +    (if b { 1 } else { 2 });
 +
 +    ({ a }) + 3;
 +    ({ a } * 2);
 +    (loop { let mut c = 0; if c == 10 { break c; } c += 1; }) + { a * 2 };
 +
 +    fn f(_: i32) {
 +        todo!();
 +    }
 +    f(a + { 8 * 5 });
 +    f(if b { 1 } else { 2 } + 3);
 +    const _: i32 = { 2 * 4 } + 3;
 +    const _: i32 = { 1 + 2 * 3 } + 3;
 +
 +    a as usize;
 +    let _ = a as usize;
 +    ({ a } as usize);
 +
 +    2 * { a };
 +    (({ a } + 4));
 +    1;
++
++    // Issue #9904
++    let x = 0i32;
++    let _: i32 = x;
 +}
 +
 +pub fn decide(a: bool, b: bool) -> u32 {
 +    (if a { 1 } else { 2 }) + if b { 3 } else { 5 }
 +}
index 9a435cdbb753f34dca293efde32429b27817e88f,0000000000000000000000000000000000000000..33201aad4f641244e93af221aff06f183ac1d470
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,123 @@@
 +// run-rustfix
 +#![warn(clippy::identity_op)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::eq_op,
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::op_ref,
 +    clippy::double_parens,
 +    clippy::uninlined_format_args
 +)]
 +
 +use std::fmt::Write as _;
 +
 +const ONE: i64 = 1;
 +const NEG_ONE: i64 = -1;
 +const ZERO: i64 = 0;
 +
 +struct A(String);
 +
 +impl std::ops::Shl<i32> for A {
 +    type Output = A;
 +    fn shl(mut self, other: i32) -> Self {
 +        let _ = write!(self.0, "{}", other);
 +        self
 +    }
 +}
 +
 +struct Length(u8);
 +struct Meter;
 +
 +impl core::ops::Mul<Meter> for u8 {
 +    type Output = Length;
 +    fn mul(self, _: Meter) -> Length {
 +        Length(self)
 +    }
 +}
 +
 +#[rustfmt::skip]
 +fn main() {
 +    let x = 0;
 +
 +    x + 0;
 +    x + (1 - 1);
 +    x + 1;
 +    0 + x;
 +    1 + x;
 +    x - ZERO; //no error, as we skip lookups (for now)
 +    x | (0);
 +    ((ZERO)) | x; //no error, as we skip lookups (for now)
 +
 +    x * 1;
 +    1 * x;
 +    x / ONE; //no error, as we skip lookups (for now)
 +
 +    x / 2; //no false positive
 +
 +    x & NEG_ONE; //no error, as we skip lookups (for now)
 +    -1 & x;
 +
 +    let u: u8 = 0;
 +    u & 255;
 +
 +    1 << 0; // no error, this case is allowed, see issue 3430
 +    42 << 0;
 +    1 >> 0;
 +    42 >> 0;
 +    &x >> 0;
 +    x >> &0;
 +
 +    let mut a = A(String::new());
 +    let b = a << 0; // no error: non-integer
 +
 +    1 * Meter; // no error: non-integer
 +
 +    2 % 3;
 +    -2 % 3;
 +    2 % -3 + x;
 +    -2 % -3 + x;
 +    x + 1 % 3;
 +    (x + 1) % 3; // no error
 +    4 % 3; // no error
 +    4 % -3; // no error
 +
 +    // See #8724
 +    let a = 0;
 +    let b = true;
 +    0 + if b { 1 } else { 2 };
 +    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
 +    0 + match a { 0 => 10, _ => 20 };
 +    0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
 +    0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
 +    0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
 +    (if b { 1 } else { 2 }) + 0;
 +
 +    0 + { a } + 3;
 +    0 + { a } * 2;
 +    0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
 +
 +    fn f(_: i32) {
 +        todo!();
 +    }
 +    f(1 * a + { 8 * 5 });
 +    f(0 + if b { 1 } else { 2 } + 3);
 +    const _: i32 = { 2 * 4 } + 0 + 3;
 +    const _: i32 = 0 + { 1 + 2 * 3 } + 3;
 +
 +    0 + a as usize;
 +    let _ = 0 + a as usize;
 +    0 + { a } as usize;
 +
 +    2 * (0 + { a });
 +    1 * ({ a } + 4);
 +    1 * 1;
++
++    // Issue #9904
++    let x = 0i32;
++    let _: i32 = &x + 0;
 +}
 +
 +pub fn decide(a: bool, b: bool) -> u32 {
 +    0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
 +}
index 1a104a20b841c1688e9412fffaf261867ef26905,0000000000000000000000000000000000000000..3ba557d18b24433c9c57bd491ffcfb44f929e9db
mode 100644,000000..100644
--- /dev/null
@@@ -1,238 -1,0 +1,244 @@@
-    |     ^^^^^^^ help: consider reducing it to: `&x`
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:43:5
 +   |
 +LL |     x + 0;
 +   |     ^^^^^ help: consider reducing it to: `x`
 +   |
 +   = note: `-D clippy::identity-op` implied by `-D warnings`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:44:5
 +   |
 +LL |     x + (1 - 1);
 +   |     ^^^^^^^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:46:5
 +   |
 +LL |     0 + x;
 +   |     ^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:49:5
 +   |
 +LL |     x | (0);
 +   |     ^^^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:52:5
 +   |
 +LL |     x * 1;
 +   |     ^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:53:5
 +   |
 +LL |     1 * x;
 +   |     ^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:59:5
 +   |
 +LL |     -1 & x;
 +   |     ^^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:62:5
 +   |
 +LL |     u & 255;
 +   |     ^^^^^^^ help: consider reducing it to: `u`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:65:5
 +   |
 +LL |     42 << 0;
 +   |     ^^^^^^^ help: consider reducing it to: `42`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:66:5
 +   |
 +LL |     1 >> 0;
 +   |     ^^^^^^ help: consider reducing it to: `1`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:67:5
 +   |
 +LL |     42 >> 0;
 +   |     ^^^^^^^ help: consider reducing it to: `42`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:68:5
 +   |
 +LL |     &x >> 0;
-   --> $DIR/identity_op.rs:118:5
++   |     ^^^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:69:5
 +   |
 +LL |     x >> &0;
 +   |     ^^^^^^^ help: consider reducing it to: `x`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:76:5
 +   |
 +LL |     2 % 3;
 +   |     ^^^^^ help: consider reducing it to: `2`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:77:5
 +   |
 +LL |     -2 % 3;
 +   |     ^^^^^^ help: consider reducing it to: `-2`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:78:5
 +   |
 +LL |     2 % -3 + x;
 +   |     ^^^^^^ help: consider reducing it to: `2`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:79:5
 +   |
 +LL |     -2 % -3 + x;
 +   |     ^^^^^^^ help: consider reducing it to: `-2`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:80:9
 +   |
 +LL |     x + 1 % 3;
 +   |         ^^^^^ help: consider reducing it to: `1`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:88:5
 +   |
 +LL |     0 + if b { 1 } else { 2 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:89:5
 +   |
 +LL |     0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:90:5
 +   |
 +LL |     0 + match a { 0 => 10, _ => 20 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:91:5
 +   |
 +LL |     0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:92:5
 +   |
 +LL |     0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:93:5
 +   |
 +LL |     0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:94:5
 +   |
 +LL |     (if b { 1 } else { 2 }) + 0;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:96:5
 +   |
 +LL |     0 + { a } + 3;
 +   |     ^^^^^^^^^ help: consider reducing it to: `({ a })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:97:5
 +   |
 +LL |     0 + { a } * 2;
 +   |     ^^^^^^^^^^^^^ help: consider reducing it to: `({ a } * 2)`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:98:5
 +   |
 +LL |     0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(loop { let mut c = 0; if c == 10 { break c; } c += 1; })`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:103:7
 +   |
 +LL |     f(1 * a + { 8 * 5 });
 +   |       ^^^^^ help: consider reducing it to: `a`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:104:7
 +   |
 +LL |     f(0 + if b { 1 } else { 2 } + 3);
 +   |       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `if b { 1 } else { 2 }`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:105:20
 +   |
 +LL |     const _: i32 = { 2 * 4 } + 0 + 3;
 +   |                    ^^^^^^^^^^^^^ help: consider reducing it to: `{ 2 * 4 }`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:106:20
 +   |
 +LL |     const _: i32 = 0 + { 1 + 2 * 3 } + 3;
 +   |                    ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `{ 1 + 2 * 3 }`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:108:5
 +   |
 +LL |     0 + a as usize;
 +   |     ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:109:13
 +   |
 +LL |     let _ = 0 + a as usize;
 +   |             ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:110:5
 +   |
 +LL |     0 + { a } as usize;
 +   |     ^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `({ a } as usize)`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:112:9
 +   |
 +LL |     2 * (0 + { a });
 +   |         ^^^^^^^^^^^ help: consider reducing it to: `{ a }`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:113:5
 +   |
 +LL |     1 * ({ a } + 4);
 +   |     ^^^^^^^^^^^^^^^ help: consider reducing it to: `(({ a } + 4))`
 +
 +error: this operation has no effect
 +  --> $DIR/identity_op.rs:114:5
 +   |
 +LL |     1 * 1;
 +   |     ^^^^^ help: consider reducing it to: `1`
 +
 +error: this operation has no effect
- error: aborting due to 39 previous errors
++  --> $DIR/identity_op.rs:118:18
++   |
++LL |     let _: i32 = &x + 0;
++   |                  ^^^^^^ help: consider reducing it to: `x`
++
++error: this operation has no effect
++  --> $DIR/identity_op.rs:122:5
 +   |
 +LL |     0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
 +
++error: aborting due to 40 previous errors
 +
index 33770fc2a2cf9cca67a956157de5fc83599d93d2,0000000000000000000000000000000000000000..51b1afbe5ac83ecaffe7bcca428f1ed8b08fa2bc
mode 100644,000000..100644
--- /dev/null
@@@ -1,118 -1,0 +1,128 @@@
 +// run-rustfix
 +#![warn(clippy::implicit_clone)]
 +#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
 +use std::borrow::Borrow;
 +use std::ffi::{OsStr, OsString};
 +use std::path::PathBuf;
 +
 +fn return_owned_from_slice(slice: &[u32]) -> Vec<u32> {
 +    slice.to_owned()
 +}
 +
 +pub fn own_same<T>(v: T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_same_from_ref<T>(v: &T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_different<T, U>(v: T) -> U
 +where
 +    T: ToOwned<Owned = U>,
 +{
 +    v.to_owned()
 +}
 +
 +#[derive(Copy, Clone)]
 +struct Kitten;
 +impl Kitten {
 +    // badly named method
 +    fn to_vec(self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +impl Borrow<BorrowedKitten> for Kitten {
 +    fn borrow(&self) -> &BorrowedKitten {
 +        static VALUE: BorrowedKitten = BorrowedKitten {};
 +        &VALUE
 +    }
 +}
 +
 +struct BorrowedKitten;
 +impl ToOwned for BorrowedKitten {
 +    type Owned = Kitten;
 +    fn to_owned(&self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +
 +mod weird {
 +    #[allow(clippy::ptr_arg)]
 +    pub fn to_vec(v: &Vec<u32>) -> Vec<u32> {
 +        v.clone()
 +    }
 +}
 +
 +fn main() {
 +    let vec = vec![5];
 +    let _ = return_owned_from_slice(&vec);
 +    let _ = vec.clone();
 +    let _ = vec.clone();
 +
 +    let vec_ref = &vec;
 +    let _ = return_owned_from_slice(vec_ref);
 +    let _ = vec_ref.clone();
 +    let _ = vec_ref.clone();
 +
 +    // we expect no lint for this
 +    let _ = weird::to_vec(&vec);
 +
 +    // we expect no lints for this
 +    let slice: &[u32] = &[1, 2, 3, 4, 5];
 +    let _ = return_owned_from_slice(slice);
 +    let _ = slice.to_owned();
 +    let _ = slice.to_vec();
 +
 +    let str = "hello world".to_string();
 +    let _ = str.clone();
 +
 +    // testing w/ an arbitrary type
 +    let kitten = Kitten {};
 +    let _ = kitten.clone();
 +    let _ = own_same_from_ref(&kitten);
 +    // this shouln't lint
 +    let _ = kitten.to_vec();
 +
 +    // we expect no lints for this
 +    let borrowed = BorrowedKitten {};
 +    let _ = borrowed.to_owned();
 +
 +    let pathbuf = PathBuf::new();
 +    let _ = pathbuf.clone();
 +    let _ = pathbuf.clone();
 +
 +    let os_string = OsString::from("foo");
 +    let _ = os_string.clone();
 +    let _ = os_string.clone();
 +
 +    // we expect no lints for this
 +    let os_str = OsStr::new("foo");
 +    let _ = os_str.to_owned();
 +    let _ = os_str.to_os_string();
 +
 +    // issue #8227
 +    let pathbuf_ref = &pathbuf;
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
 +    let _ = (*pathbuf_ref).clone();
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
 +    let _ = (**pathbuf_ref).clone();
++
++    struct NoClone;
++    impl ToOwned for NoClone {
++        type Owned = Self;
++        fn to_owned(&self) -> Self {
++            NoClone
++        }
++    }
++    let no_clone = &NoClone;
++    let _ = no_clone.to_owned();
 +}
index fc896525bd2709ba82b41b56073bf8418649488e,0000000000000000000000000000000000000000..8a9027433d95be632772e54ef97025e8e8a58df1
mode 100644,000000..100644
--- /dev/null
@@@ -1,118 -1,0 +1,128 @@@
 +// run-rustfix
 +#![warn(clippy::implicit_clone)]
 +#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
 +use std::borrow::Borrow;
 +use std::ffi::{OsStr, OsString};
 +use std::path::PathBuf;
 +
 +fn return_owned_from_slice(slice: &[u32]) -> Vec<u32> {
 +    slice.to_owned()
 +}
 +
 +pub fn own_same<T>(v: T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_same_from_ref<T>(v: &T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_different<T, U>(v: T) -> U
 +where
 +    T: ToOwned<Owned = U>,
 +{
 +    v.to_owned()
 +}
 +
 +#[derive(Copy, Clone)]
 +struct Kitten;
 +impl Kitten {
 +    // badly named method
 +    fn to_vec(self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +impl Borrow<BorrowedKitten> for Kitten {
 +    fn borrow(&self) -> &BorrowedKitten {
 +        static VALUE: BorrowedKitten = BorrowedKitten {};
 +        &VALUE
 +    }
 +}
 +
 +struct BorrowedKitten;
 +impl ToOwned for BorrowedKitten {
 +    type Owned = Kitten;
 +    fn to_owned(&self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +
 +mod weird {
 +    #[allow(clippy::ptr_arg)]
 +    pub fn to_vec(v: &Vec<u32>) -> Vec<u32> {
 +        v.clone()
 +    }
 +}
 +
 +fn main() {
 +    let vec = vec![5];
 +    let _ = return_owned_from_slice(&vec);
 +    let _ = vec.to_owned();
 +    let _ = vec.to_vec();
 +
 +    let vec_ref = &vec;
 +    let _ = return_owned_from_slice(vec_ref);
 +    let _ = vec_ref.to_owned();
 +    let _ = vec_ref.to_vec();
 +
 +    // we expect no lint for this
 +    let _ = weird::to_vec(&vec);
 +
 +    // we expect no lints for this
 +    let slice: &[u32] = &[1, 2, 3, 4, 5];
 +    let _ = return_owned_from_slice(slice);
 +    let _ = slice.to_owned();
 +    let _ = slice.to_vec();
 +
 +    let str = "hello world".to_string();
 +    let _ = str.to_owned();
 +
 +    // testing w/ an arbitrary type
 +    let kitten = Kitten {};
 +    let _ = kitten.to_owned();
 +    let _ = own_same_from_ref(&kitten);
 +    // this shouln't lint
 +    let _ = kitten.to_vec();
 +
 +    // we expect no lints for this
 +    let borrowed = BorrowedKitten {};
 +    let _ = borrowed.to_owned();
 +
 +    let pathbuf = PathBuf::new();
 +    let _ = pathbuf.to_owned();
 +    let _ = pathbuf.to_path_buf();
 +
 +    let os_string = OsString::from("foo");
 +    let _ = os_string.to_owned();
 +    let _ = os_string.to_os_string();
 +
 +    // we expect no lints for this
 +    let os_str = OsStr::new("foo");
 +    let _ = os_str.to_owned();
 +    let _ = os_str.to_os_string();
 +
 +    // issue #8227
 +    let pathbuf_ref = &pathbuf;
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
 +    let _ = pathbuf_ref.to_path_buf();
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
 +    let _ = pathbuf_ref.to_path_buf();
++
++    struct NoClone;
++    impl ToOwned for NoClone {
++        type Owned = Self;
++        fn to_owned(&self) -> Self {
++            NoClone
++        }
++    }
++    let no_clone = &NoClone;
++    let _ = no_clone.to_owned();
 +}
index 4476e0eb9220a636eb6c813ec414e661584c8c79,0000000000000000000000000000000000000000..26abc9edb5e445f16976d94e032d33003388166d
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,48 @@@
- const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
 +#![feature(inline_const)]
 +#![warn(clippy::indexing_slicing)]
 +// We also check the out_of_bounds_indexing lint here, because it lints similar things and
 +// we want to avoid false positives.
 +#![warn(clippy::out_of_bounds_indexing)]
 +#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
 +
 +const ARR: [i32; 2] = [1, 2];
-     const { &ARR[idx()] }; // Ok, should not produce stderr.
-     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
++const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 +const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
 +
 +const fn idx() -> usize {
 +    1
 +}
 +const fn idx4() -> usize {
 +    4
 +}
 +
 +fn main() {
 +    let x = [1, 2, 3, 4];
 +    let index: usize = 1;
 +    x[index];
 +    x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
 +    x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
 +
 +    x[0]; // Ok, should not produce stderr.
 +    x[3]; // Ok, should not produce stderr.
 +    x[const { idx() }]; // Ok, should not produce stderr.
 +    x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
++    const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 +
 +    let y = &x;
 +    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
 +    y[4]; // Ok, rustc will handle references too.
 +
 +    let v = vec![0; 5];
 +    v[0];
 +    v[10];
 +    v[1 << 3];
 +
 +    const N: usize = 15; // Out of bounds
 +    const M: usize = 3; // In bounds
 +    x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
 +    x[M]; // Ok, should not produce stderr.
 +    v[N];
 +    v[M];
 +}
index d8b6e3f1262b735345660276aa3456cb759aad52,0000000000000000000000000000000000000000..8fd77913a3fd97626ed617357380b578ab13ef1c
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,106 @@@
- LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
++error: indexing may panic
++  --> $DIR/indexing_slicing_index.rs:9:20
++   |
++LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
++   |                    ^^^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++   = note: the suggestion might not be applicable in constant blocks
++   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
++
++error: indexing may panic
++  --> $DIR/indexing_slicing_index.rs:10:24
++   |
++LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
++   |                        ^^^^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++   = note: the suggestion might not be applicable in constant blocks
++
 +error[E0080]: evaluation of `main::{constant#3}` failed
 +  --> $DIR/indexing_slicing_index.rs:31:14
 +   |
- LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
++LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 +   |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 +
 +note: erroneous constant used
 +  --> $DIR/indexing_slicing_index.rs:31:5
 +   |
-    = note: `-D clippy::indexing-slicing` implied by `-D warnings`
++LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 +   |     ^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:22:5
 +   |
 +LL |     x[index];
 +   |     ^^^^^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
- error: aborting due to 8 previous errors
++
++error: indexing may panic
++  --> $DIR/indexing_slicing_index.rs:30:14
++   |
++LL |     const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
++   |              ^^^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++   = note: the suggestion might not be applicable in constant blocks
++
++error: indexing may panic
++  --> $DIR/indexing_slicing_index.rs:31:14
++   |
++LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
++   |              ^^^^^^^^^^^
++   |
++   = help: consider using `.get(n)` or `.get_mut(n)` instead
++   = note: the suggestion might not be applicable in constant blocks
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:38:5
 +   |
 +LL |     v[0];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:39:5
 +   |
 +LL |     v[10];
 +   |     ^^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:40:5
 +   |
 +LL |     v[1 << 3];
 +   |     ^^^^^^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:46:5
 +   |
 +LL |     v[N];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
 +  --> $DIR/indexing_slicing_index.rs:47:5
 +   |
 +LL |     v[M];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error[E0080]: evaluation of constant value failed
 +  --> $DIR/indexing_slicing_index.rs:10:24
 +   |
 +LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
 +   |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 +
++error: aborting due to 12 previous errors
 +
 +For more information about this error, try `rustc --explain E0080`.
index 1f3b8ac99b19146f766e6758d0cd799d37dc92c0,0000000000000000000000000000000000000000..c1c0b5ae40f6170b4b9d4daa0dd5424f661b8fa7
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,183 @@@
 +// run-rustfix
 +
 +#![warn(clippy::len_zero)]
 +#![allow(dead_code, unused, clippy::len_without_is_empty)]
 +
++extern crate core;
++use core::ops::Deref;
++
 +pub struct One;
 +struct Wither;
 +
 +trait TraitsToo {
 +    fn len(&self) -> isize;
 +    // No error; `len` is private; see issue #1085.
 +}
 +
 +impl TraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +pub struct HasIsEmpty;
 +
 +impl HasIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct HasWrongIsEmpty;
 +
 +impl HasWrongIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self, x: u32) -> bool {
 +        false
 +    }
 +}
 +
 +pub trait WithIsEmpty {
 +    fn len(&self) -> isize;
 +    fn is_empty(&self) -> bool;
 +}
 +
 +impl WithIsEmpty for Wither {
 +    fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
++struct DerefToDerefToString;
++
++impl Deref for DerefToDerefToString {
++    type Target = DerefToString;
++
++    fn deref(&self) -> &Self::Target {
++        &DerefToString {}
++    }
++}
++
++struct DerefToString;
++
++impl Deref for DerefToString {
++    type Target = str;
++
++    fn deref(&self) -> &Self::Target {
++        "Hello, world!"
++    }
++}
++
 +fn main() {
 +    let x = [1, 2];
 +    if x.is_empty() {
 +        println!("This should not happen!");
 +    }
 +
 +    if "".is_empty() {}
 +
++    let s = "Hello, world!";
++    let s1 = &s;
++    let s2 = &s1;
++    let s3 = &s2;
++    let s4 = &s3;
++    let s5 = &s4;
++    let s6 = &s5;
++    println!("{}", s1.is_empty());
++    println!("{}", s2.is_empty());
++    println!("{}", s3.is_empty());
++    println!("{}", s4.is_empty());
++    println!("{}", s5.is_empty());
++    println!("{}", (s6).is_empty());
++
++    let d2s = DerefToDerefToString {};
++    println!("{}", (**d2s).is_empty());
++
 +    let y = One;
 +    if y.len() == 0 {
 +        // No error; `One` does not have `.is_empty()`.
 +        println!("This should not happen either!");
 +    }
 +
 +    let z: &dyn TraitsToo = &y;
 +    if z.len() > 0 {
 +        // No error; `TraitsToo` has no `.is_empty()` method.
 +        println!("Nor should this!");
 +    }
 +
 +    let has_is_empty = HasIsEmpty;
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.len() <= 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if 1 < has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 1 >= has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    assert!(!has_is_empty.is_empty());
 +
 +    let with_is_empty: &dyn WithIsEmpty = &Wither;
 +    if with_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    assert!(!with_is_empty.is_empty());
 +
 +    let has_wrong_is_empty = HasWrongIsEmpty;
 +    if has_wrong_is_empty.len() == 0 {
 +        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
 +        println!("Or this!");
 +    }
 +}
 +
 +fn test_slice(b: &[u8]) {
 +    if !b.is_empty() {}
 +}
index dc21de0001b6c76eb2f57cdba4e7416319d5b756,0000000000000000000000000000000000000000..cc2eb05b6bfd2ee81c35ea7754118532dd5f7ab9
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,183 @@@
 +// run-rustfix
 +
 +#![warn(clippy::len_zero)]
 +#![allow(dead_code, unused, clippy::len_without_is_empty)]
 +
++extern crate core;
++use core::ops::Deref;
++
 +pub struct One;
 +struct Wither;
 +
 +trait TraitsToo {
 +    fn len(&self) -> isize;
 +    // No error; `len` is private; see issue #1085.
 +}
 +
 +impl TraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +pub struct HasIsEmpty;
 +
 +impl HasIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct HasWrongIsEmpty;
 +
 +impl HasWrongIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self, x: u32) -> bool {
 +        false
 +    }
 +}
 +
 +pub trait WithIsEmpty {
 +    fn len(&self) -> isize;
 +    fn is_empty(&self) -> bool;
 +}
 +
 +impl WithIsEmpty for Wither {
 +    fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
++struct DerefToDerefToString;
++
++impl Deref for DerefToDerefToString {
++    type Target = DerefToString;
++
++    fn deref(&self) -> &Self::Target {
++        &DerefToString {}
++    }
++}
++
++struct DerefToString;
++
++impl Deref for DerefToString {
++    type Target = str;
++
++    fn deref(&self) -> &Self::Target {
++        "Hello, world!"
++    }
++}
++
 +fn main() {
 +    let x = [1, 2];
 +    if x.len() == 0 {
 +        println!("This should not happen!");
 +    }
 +
 +    if "".len() == 0 {}
 +
++    let s = "Hello, world!";
++    let s1 = &s;
++    let s2 = &s1;
++    let s3 = &s2;
++    let s4 = &s3;
++    let s5 = &s4;
++    let s6 = &s5;
++    println!("{}", *s1 == "");
++    println!("{}", **s2 == "");
++    println!("{}", ***s3 == "");
++    println!("{}", ****s4 == "");
++    println!("{}", *****s5 == "");
++    println!("{}", ******(s6) == "");
++
++    let d2s = DerefToDerefToString {};
++    println!("{}", &**d2s == "");
++
 +    let y = One;
 +    if y.len() == 0 {
 +        // No error; `One` does not have `.is_empty()`.
 +        println!("This should not happen either!");
 +    }
 +
 +    let z: &dyn TraitsToo = &y;
 +    if z.len() > 0 {
 +        // No error; `TraitsToo` has no `.is_empty()` method.
 +        println!("Nor should this!");
 +    }
 +
 +    let has_is_empty = HasIsEmpty;
 +    if has_is_empty.len() == 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() != 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() < 1 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() >= 1 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.len() <= 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 0 == has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 0 != has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 0 < has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 <= has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 > has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 < has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 1 >= has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    assert!(!has_is_empty.is_empty());
 +
 +    let with_is_empty: &dyn WithIsEmpty = &Wither;
 +    if with_is_empty.len() == 0 {
 +        println!("Or this!");
 +    }
 +    assert!(!with_is_empty.is_empty());
 +
 +    let has_wrong_is_empty = HasWrongIsEmpty;
 +    if has_wrong_is_empty.len() == 0 {
 +        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
 +        println!("Or this!");
 +    }
 +}
 +
 +fn test_slice(b: &[u8]) {
 +    if b.len() != 0 {}
 +}
index 6c71f1beeac67c27a89916538cbdfcc2af70d896,0000000000000000000000000000000000000000..b6f13780253c2e526533179cc5602c0ff557f68a
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,132 @@@
-   --> $DIR/len_zero.rs:61:8
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:65:8
++  --> $DIR/len_zero.rs:84:8
 +   |
 +LL |     if x.len() == 0 {
 +   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
 +   |
 +   = note: `-D clippy::len-zero` implied by `-D warnings`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:80:8
++  --> $DIR/len_zero.rs:88:8
 +   |
 +LL |     if "".len() == 0 {}
 +   |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
 +
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:97:20
++   |
++LL |     println!("{}", *s1 == "");
++   |                    ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
++   |
++   = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:98:20
++   |
++LL |     println!("{}", **s2 == "");
++   |                    ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:99:20
++   |
++LL |     println!("{}", ***s3 == "");
++   |                    ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:100:20
++   |
++LL |     println!("{}", ****s4 == "");
++   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:101:20
++   |
++LL |     println!("{}", *****s5 == "");
++   |                    ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:102:20
++   |
++LL |     println!("{}", ******(s6) == "");
++   |                    ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
++
++error: comparison to empty slice
++  --> $DIR/len_zero.rs:105:20
++   |
++LL |     println!("{}", &**d2s == "");
++   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
++
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:83:8
++  --> $DIR/len_zero.rs:120:8
 +   |
 +LL |     if has_is_empty.len() == 0 {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:86:8
++  --> $DIR/len_zero.rs:123:8
 +   |
 +LL |     if has_is_empty.len() != 0 {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:89:8
++  --> $DIR/len_zero.rs:126:8
 +   |
 +LL |     if has_is_empty.len() > 0 {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to one
-   --> $DIR/len_zero.rs:92:8
++  --> $DIR/len_zero.rs:129:8
 +   |
 +LL |     if has_is_empty.len() < 1 {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 +
 +error: length comparison to one
-   --> $DIR/len_zero.rs:103:8
++  --> $DIR/len_zero.rs:132:8
 +   |
 +LL |     if has_is_empty.len() >= 1 {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:106:8
++  --> $DIR/len_zero.rs:143:8
 +   |
 +LL |     if 0 == has_is_empty.len() {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:109:8
++  --> $DIR/len_zero.rs:146:8
 +   |
 +LL |     if 0 != has_is_empty.len() {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:112:8
++  --> $DIR/len_zero.rs:149:8
 +   |
 +LL |     if 0 < has_is_empty.len() {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to one
-   --> $DIR/len_zero.rs:115:8
++  --> $DIR/len_zero.rs:152:8
 +   |
 +LL |     if 1 <= has_is_empty.len() {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 +
 +error: length comparison to one
-   --> $DIR/len_zero.rs:129:8
++  --> $DIR/len_zero.rs:155:8
 +   |
 +LL |     if 1 > has_is_empty.len() {
 +   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 +
 +error: length comparison to zero
-   --> $DIR/len_zero.rs:142:8
++  --> $DIR/len_zero.rs:169:8
 +   |
 +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
- error: aborting due to 14 previous errors
++  --> $DIR/len_zero.rs:182: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
 +
index c9a819ba535449a1b8d90b2324204f74b318a585,0000000000000000000000000000000000000000..638320dd6eec439a76ea745736dd2b7fcfd1672f
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,82 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::manual_assert)]
 +#![allow(dead_code, unused_doc_comments)]
 +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
 +
 +macro_rules! one {
 +    () => {
 +        1
 +    };
 +}
 +
 +fn main() {
 +    let a = vec![1, 2, 3];
 +    let c = Some(2);
 +    if !a.is_empty()
 +        && a.len() == 3
 +        && c.is_some()
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +    {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    assert!(a.is_empty(), "qaqaq{:?}", a);
 +    if !a.is_empty() {
 +        panic!("qwqwq");
 +    }
 +    if a.len() == 3 {
 +        println!("qwq");
 +        println!("qwq");
 +        println!("qwq");
 +    }
 +    if let Some(b) = c {
 +        panic!("orz {}", b);
 +    }
 +    if a.len() == 3 {
 +        panic!("qaqaq");
 +    } else {
 +        println!("qwq");
 +    }
 +    let b = vec![1, 2, 3];
 +    if b.is_empty() {
 +        panic!("panic1");
 +    }
 +    if b.is_empty() && a.is_empty() {
 +        panic!("panic2");
 +    }
 +    if a.is_empty() && !b.is_empty() {
 +        panic!("panic3");
 +    }
 +    if b.is_empty() || a.is_empty() {
 +        panic!("panic4");
 +    }
 +    if a.is_empty() || !b.is_empty() {
 +        panic!("panic5");
 +    }
 +    assert!(!a.is_empty(), "with expansion {}", one!());
++    if a.is_empty() {
++        let _ = 0;
++    } else if a.len() == 1 {
++        panic!("panic6");
++    }
 +}
 +
 +fn issue7730(a: u8) {
 +    // Suggestion should preserve comment
 +    if a > 2 {
 +        // comment
 +        /* this is a
 +        multiline
 +        comment */
 +        /// Doc comment
 +        panic!("panic with comment") // comment after `panic!`
 +    }
 +}
index 2f62de51cadcd948a98c0b75668aa2f13c6b4a92,0000000000000000000000000000000000000000..8c7e919bf62a10d52bc6a343454b438f89c8857b
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,69 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::manual_assert)]
 +#![allow(dead_code, unused_doc_comments)]
 +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
 +
 +macro_rules! one {
 +    () => {
 +        1
 +    };
 +}
 +
 +fn main() {
 +    let a = vec![1, 2, 3];
 +    let c = Some(2);
 +    if !a.is_empty()
 +        && a.len() == 3
 +        && c.is_some()
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +    {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    assert!(a.is_empty(), "qaqaq{:?}", a);
 +    assert!(a.is_empty(), "qwqwq");
 +    if a.len() == 3 {
 +        println!("qwq");
 +        println!("qwq");
 +        println!("qwq");
 +    }
 +    if let Some(b) = c {
 +        panic!("orz {}", b);
 +    }
 +    if a.len() == 3 {
 +        panic!("qaqaq");
 +    } else {
 +        println!("qwq");
 +    }
 +    let b = vec![1, 2, 3];
 +    assert!(!b.is_empty(), "panic1");
 +    assert!(!(b.is_empty() && a.is_empty()), "panic2");
 +    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
 +    assert!(!(b.is_empty() || a.is_empty()), "panic4");
 +    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
 +    assert!(!a.is_empty(), "with expansion {}", one!());
++    if a.is_empty() {
++        let _ = 0;
++    } else if a.len() == 1 {
++        panic!("panic6");
++    }
 +}
 +
 +fn issue7730(a: u8) {
 +    // Suggestion should preserve comment
 +    // comment
 +/* this is a
 +        multiline
 +        comment */
 +/// Doc comment
 +// comment after `panic!`
 +assert!(!(a > 2), "panic with comment");
 +}
index 237638ee1344c60274bb31c1accbcf7f7456cee3,0000000000000000000000000000000000000000..3555ac29243a1cb0d819a368d8bb22bf02aea2de
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,85 @@@
-   --> $DIR/manual_assert.rs:73:5
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:31:5
 +   |
 +LL | /     if !a.is_empty() {
 +LL | |         panic!("qaqaq{:?}", a);
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);`
 +   |
 +   = note: `-D clippy::manual-assert` implied by `-D warnings`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:34:5
 +   |
 +LL | /     if !a.is_empty() {
 +LL | |         panic!("qwqwq");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:51:5
 +   |
 +LL | /     if b.is_empty() {
 +LL | |         panic!("panic1");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:54:5
 +   |
 +LL | /     if b.is_empty() && a.is_empty() {
 +LL | |         panic!("panic2");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:57:5
 +   |
 +LL | /     if a.is_empty() && !b.is_empty() {
 +LL | |         panic!("panic3");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:60:5
 +   |
 +LL | /     if b.is_empty() || a.is_empty() {
 +LL | |         panic!("panic4");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:63:5
 +   |
 +LL | /     if a.is_empty() || !b.is_empty() {
 +LL | |         panic!("panic5");
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/manual_assert.rs:66:5
 +   |
 +LL | /     if a.is_empty() {
 +LL | |         panic!("with expansion {}", one!())
 +LL | |     }
 +   | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 +
 +error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:78:5
 +   |
 +LL | /     if a > 2 {
 +LL | |         // comment
 +LL | |         /* this is a
 +LL | |         multiline
 +...  |
 +LL | |         panic!("panic with comment") // comment after `panic!`
 +LL | |     }
 +   | |_____^
 +   |
 +help: try instead
 +   |
 +LL |     assert!(!(a > 2), "panic with comment");
 +   |
 +
 +error: aborting due to 9 previous errors
 +
index 6a4cc2468d4193815b6b43299db873b95d8fb33d,0000000000000000000000000000000000000000..f037c5b8405c721cc6755b1874cf5d47f229206b
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,86 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::manual_assert)]
 +#![allow(dead_code, unused_doc_comments)]
 +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
 +
 +macro_rules! one {
 +    () => {
 +        1
 +    };
 +}
 +
 +fn main() {
 +    let a = vec![1, 2, 3];
 +    let c = Some(2);
 +    if !a.is_empty()
 +        && a.len() == 3
 +        && c.is_some()
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +    {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    if !a.is_empty() {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    if !a.is_empty() {
 +        panic!("qwqwq");
 +    }
 +    if a.len() == 3 {
 +        println!("qwq");
 +        println!("qwq");
 +        println!("qwq");
 +    }
 +    if let Some(b) = c {
 +        panic!("orz {}", b);
 +    }
 +    if a.len() == 3 {
 +        panic!("qaqaq");
 +    } else {
 +        println!("qwq");
 +    }
 +    let b = vec![1, 2, 3];
 +    if b.is_empty() {
 +        panic!("panic1");
 +    }
 +    if b.is_empty() && a.is_empty() {
 +        panic!("panic2");
 +    }
 +    if a.is_empty() && !b.is_empty() {
 +        panic!("panic3");
 +    }
 +    if b.is_empty() || a.is_empty() {
 +        panic!("panic4");
 +    }
 +    if a.is_empty() || !b.is_empty() {
 +        panic!("panic5");
 +    }
 +    if a.is_empty() {
 +        panic!("with expansion {}", one!())
 +    }
++    if a.is_empty() {
++        let _ = 0;
++    } else if a.len() == 1 {
++        panic!("panic6");
++    }
 +}
 +
 +fn issue7730(a: u8) {
 +    // Suggestion should preserve comment
 +    if a > 2 {
 +        // comment
 +        /* this is a
 +        multiline
 +        comment */
 +        /// Doc comment
 +        panic!("panic with comment") // comment after `panic!`
 +    }
 +}
index 231ba83b1426130a3b6482d8e9cb938aacfced4d,0000000000000000000000000000000000000000..5b2b44c2fdb2bbaa6c960d482f36e051616267fe
mode 100644,000000..100644
--- /dev/null
@@@ -1,42 -1,0 +1,55 @@@
 +// run-rustfix
 +
 +#![allow(unused, dead_code)]
 +#![warn(clippy::manual_is_ascii_check)]
 +
 +fn main() {
 +    assert!('x'.is_ascii_lowercase());
 +    assert!('X'.is_ascii_uppercase());
 +    assert!(b'x'.is_ascii_lowercase());
 +    assert!(b'X'.is_ascii_uppercase());
 +
 +    let num = '2';
 +    assert!(num.is_ascii_digit());
 +    assert!(b'1'.is_ascii_digit());
 +    assert!('x'.is_ascii_alphabetic());
 +
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
++
++    b'0'.is_ascii_digit();
++    b'a'.is_ascii_lowercase();
++    b'A'.is_ascii_uppercase();
++
++    '0'.is_ascii_digit();
++    'a'.is_ascii_lowercase();
++    'A'.is_ascii_uppercase();
++
++    let cool_letter = &'g';
++    cool_letter.is_ascii_digit();
++    cool_letter.is_ascii_lowercase();
++    cool_letter.is_ascii_uppercase();
 +}
 +
 +#[clippy::msrv = "1.23"]
 +fn msrv_1_23() {
 +    assert!(matches!(b'1', b'0'..=b'9'));
 +    assert!(matches!('X', 'A'..='Z'));
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +}
 +
 +#[clippy::msrv = "1.24"]
 +fn msrv_1_24() {
 +    assert!(b'1'.is_ascii_digit());
 +    assert!('X'.is_ascii_uppercase());
 +    assert!('x'.is_ascii_alphabetic());
 +}
 +
 +#[clippy::msrv = "1.46"]
 +fn msrv_1_46() {
 +    const FOO: bool = matches!('x', '0'..='9');
 +}
 +
 +#[clippy::msrv = "1.47"]
 +fn msrv_1_47() {
 +    const FOO: bool = 'x'.is_ascii_digit();
 +}
index 39ee6151c56f08ff53b77377e9eb916b437d00a6,0000000000000000000000000000000000000000..c9433f33a1b6f3891e47a391ad150a784c2bc0db
mode 100644,000000..100644
--- /dev/null
@@@ -1,42 -1,0 +1,55 @@@
 +// run-rustfix
 +
 +#![allow(unused, dead_code)]
 +#![warn(clippy::manual_is_ascii_check)]
 +
 +fn main() {
 +    assert!(matches!('x', 'a'..='z'));
 +    assert!(matches!('X', 'A'..='Z'));
 +    assert!(matches!(b'x', b'a'..=b'z'));
 +    assert!(matches!(b'X', b'A'..=b'Z'));
 +
 +    let num = '2';
 +    assert!(matches!(num, '0'..='9'));
 +    assert!(matches!(b'1', b'0'..=b'9'));
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
++
++    (b'0'..=b'9').contains(&b'0');
++    (b'a'..=b'z').contains(&b'a');
++    (b'A'..=b'Z').contains(&b'A');
++
++    ('0'..='9').contains(&'0');
++    ('a'..='z').contains(&'a');
++    ('A'..='Z').contains(&'A');
++
++    let cool_letter = &'g';
++    ('0'..='9').contains(cool_letter);
++    ('a'..='z').contains(cool_letter);
++    ('A'..='Z').contains(cool_letter);
 +}
 +
 +#[clippy::msrv = "1.23"]
 +fn msrv_1_23() {
 +    assert!(matches!(b'1', b'0'..=b'9'));
 +    assert!(matches!('X', 'A'..='Z'));
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +}
 +
 +#[clippy::msrv = "1.24"]
 +fn msrv_1_24() {
 +    assert!(matches!(b'1', b'0'..=b'9'));
 +    assert!(matches!('X', 'A'..='Z'));
 +    assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +}
 +
 +#[clippy::msrv = "1.46"]
 +fn msrv_1_46() {
 +    const FOO: bool = matches!('x', '0'..='9');
 +}
 +
 +#[clippy::msrv = "1.47"]
 +fn msrv_1_47() {
 +    const FOO: bool = matches!('x', '0'..='9');
 +}
index 397cbe05c822ad7fba97b5f46d02fd569e2882fe,0000000000000000000000000000000000000000..ee60188506d6fc08182a897d47a9d3c7ca290aa4
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,124 @@@
-   --> $DIR/manual_is_ascii_check.rs:29:13
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:7:13
 +   |
 +LL |     assert!(matches!('x', 'a'..='z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_lowercase()`
 +   |
 +   = note: `-D clippy::manual-is-ascii-check` implied by `-D warnings`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:8:13
 +   |
 +LL |     assert!(matches!('X', 'A'..='Z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:9:13
 +   |
 +LL |     assert!(matches!(b'x', b'a'..=b'z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'x'.is_ascii_lowercase()`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:10:13
 +   |
 +LL |     assert!(matches!(b'X', b'A'..=b'Z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'X'.is_ascii_uppercase()`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:13:13
 +   |
 +LL |     assert!(matches!(num, '0'..='9'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.is_ascii_digit()`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:14:13
 +   |
 +LL |     assert!(matches!(b'1', b'0'..=b'9'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 +
 +error: manual check for common ascii range
 +  --> $DIR/manual_is_ascii_check.rs:15:13
 +   |
 +LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 +
 +error: manual check for common ascii range
-   --> $DIR/manual_is_ascii_check.rs:30:13
++  --> $DIR/manual_is_ascii_check.rs:19:5
++   |
++LL |     (b'0'..=b'9').contains(&b'0');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:20:5
++   |
++LL |     (b'a'..=b'z').contains(&b'a');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:21:5
++   |
++LL |     (b'A'..=b'Z').contains(&b'A');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:23:5
++   |
++LL |     ('0'..='9').contains(&'0');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:24:5
++   |
++LL |     ('a'..='z').contains(&'a');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:25:5
++   |
++LL |     ('A'..='Z').contains(&'A');
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:28:5
++   |
++LL |     ('0'..='9').contains(cool_letter);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:29:5
++   |
++LL |     ('a'..='z').contains(cool_letter);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:30:5
++   |
++LL |     ('A'..='Z').contains(cool_letter);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
++
++error: manual check for common ascii range
++  --> $DIR/manual_is_ascii_check.rs:42:13
 +   |
 +LL |     assert!(matches!(b'1', b'0'..=b'9'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 +
 +error: manual check for common ascii range
-   --> $DIR/manual_is_ascii_check.rs:31:13
++  --> $DIR/manual_is_ascii_check.rs:43:13
 +   |
 +LL |     assert!(matches!('X', 'A'..='Z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 +
 +error: manual check for common ascii range
-   --> $DIR/manual_is_ascii_check.rs:41:23
++  --> $DIR/manual_is_ascii_check.rs:44:13
 +   |
 +LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 +
 +error: manual check for common ascii range
- error: aborting due to 11 previous errors
++  --> $DIR/manual_is_ascii_check.rs:54:23
 +   |
 +LL |     const FOO: bool = matches!('x', '0'..='9');
 +   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
 +
++error: aborting due to 20 previous errors
 +
index 93c86ca24fea3a079c80c8ae7bb32204b29f6be3,0000000000000000000000000000000000000000..28caed9d79df244f074eab27b108794139ca3ac2
mode 100644,000000..100644
--- /dev/null
@@@ -1,121 -1,0 +1,128 @@@
 +#![allow(unused_braces, unused_variables, dead_code)]
 +#![allow(clippy::collapsible_else_if, clippy::let_unit_value)]
 +#![warn(clippy::manual_let_else)]
 +// Ensure that we don't conflict with match -> if let lints
 +#![warn(clippy::single_match_else, clippy::single_match)]
 +
 +fn f() -> Result<u32, u32> {
 +    Ok(0)
 +}
 +
 +fn g() -> Option<()> {
 +    None
 +}
 +
 +fn h() -> (Option<()>, Option<()>) {
 +    (None, None)
 +}
 +
 +enum Variant {
 +    Foo,
 +    Bar(u32),
 +    Baz(u32),
 +}
 +
 +fn build_enum() -> Variant {
 +    Variant::Foo
 +}
 +
 +fn main() {}
 +
 +fn fire() {
 +    let v = match g() {
 +        Some(v_some) => v_some,
 +        None => return,
 +    };
 +
 +    let v = match g() {
 +        Some(v_some) => v_some,
 +        _ => return,
 +    };
 +
 +    loop {
 +        // More complex pattern for the identity arm and diverging arm
 +        let v = match h() {
 +            (Some(_), Some(_)) | (None, None) => continue,
 +            (Some(v), None) | (None, Some(v)) => v,
 +        };
 +        // Custom enums are supported as long as the "else" arm is a simple _
 +        let v = match build_enum() {
 +            _ => continue,
 +            Variant::Bar(v) | Variant::Baz(v) => v,
 +        };
 +    }
 +
 +    // There is a _ in the diverging arm
 +    // TODO also support unused bindings aka _v
 +    let v = match f() {
 +        Ok(v) => v,
 +        Err(_) => return,
 +    };
 +
 +    // Err(()) is an allowed pattern
 +    let v = match f().map_err(|_| ()) {
 +        Ok(v) => v,
 +        Err(()) => return,
 +    };
++
++    let f = Variant::Bar(1);
++
++    let _value = match f {
++        Variant::Bar(_) | Variant::Baz(_) => (),
++        _ => return,
++    };
 +}
 +
 +fn not_fire() {
 +    // Multiple diverging arms
 +    let v = match h() {
 +        _ => panic!(),
 +        (None, Some(_v)) => return,
 +        (Some(v), None) => v,
 +    };
 +
 +    // Multiple identity arms
 +    let v = match h() {
 +        _ => panic!(),
 +        (None, Some(v)) => v,
 +        (Some(v), None) => v,
 +    };
 +
 +    // No diverging arm at all, only identity arms.
 +    // This is no case for let else, but destructuring assignment.
 +    let v = match f() {
 +        Ok(v) => v,
 +        Err(e) => e,
 +    };
 +
 +    // The identity arm has a guard
 +    let v = match g() {
 +        Some(v) if g().is_none() => v,
 +        _ => return,
 +    };
 +
 +    // The diverging arm has a guard
 +    let v = match f() {
 +        Err(v) if v > 0 => panic!(),
 +        Ok(v) | Err(v) => v,
 +    };
 +
 +    // The diverging arm creates a binding
 +    let v = match f() {
 +        Ok(v) => v,
 +        Err(e) => panic!("error: {e}"),
 +    };
 +
 +    // Custom enum where the diverging arm
 +    // explicitly mentions the variant
 +    let v = match build_enum() {
 +        Variant::Foo => return,
 +        Variant::Bar(v) | Variant::Baz(v) => v,
 +    };
 +
 +    // The custom enum is surrounded by an Err()
 +    let v = match Err(build_enum()) {
 +        Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
 +        Err(Variant::Foo) => return,
 +    };
 +}
index 38be5ac54547368b7fe98d336a1da5acc2e85db7,0000000000000000000000000000000000000000..cd5e9a9ac39c0770fcd41351097e381cfe0f6ec4
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,67 @@@
-    | |__________^ help: consider writing: `let (Some(v), None) | (None, Some(v)) = h() else { continue };`
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:32:5
 +   |
 +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 };`
 +   |
 +   = note: `-D clippy::manual-let-else` implied by `-D warnings`
 +
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:37:5
 +   |
 +LL | /     let v = match g() {
 +LL | |         Some(v_some) => v_some,
 +LL | |         _ => return,
 +LL | |     };
 +   | |______^ help: consider writing: `let Some(v_some) = g() else { return };`
 +
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:44:9
 +   |
 +LL | /         let v = match h() {
 +LL | |             (Some(_), Some(_)) | (None, None) => continue,
 +LL | |             (Some(v), None) | (None, Some(v)) => v,
 +LL | |         };
-    | |__________^ help: consider writing: `let Variant::Bar(v) | Variant::Baz(v) = build_enum() else { continue };`
++   | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
 +
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:49:9
 +   |
 +LL | /         let v = match build_enum() {
 +LL | |             _ => continue,
 +LL | |             Variant::Bar(v) | Variant::Baz(v) => v,
 +LL | |         };
- error: aborting due to 6 previous errors
++   | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
 +
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:57:5
 +   |
 +LL | /     let v = match f() {
 +LL | |         Ok(v) => v,
 +LL | |         Err(_) => return,
 +LL | |     };
 +   | |______^ help: consider writing: `let Ok(v) = f() else { return };`
 +
 +error: this could be rewritten as `let...else`
 +  --> $DIR/manual_let_else_match.rs:63:5
 +   |
 +LL | /     let v = match f().map_err(|_| ()) {
 +LL | |         Ok(v) => v,
 +LL | |         Err(()) => return,
 +LL | |     };
 +   | |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };`
 +
++error: this could be rewritten as `let...else`
++  --> $DIR/manual_let_else_match.rs:70:5
++   |
++LL | /     let _value = match f {
++LL | |         Variant::Bar(_) | Variant::Baz(_) => (),
++LL | |         _ => return,
++LL | |     };
++   | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
++
++error: aborting due to 7 previous errors
 +
index 1bd75c806bc94378acadd7f86e5bc533de7548e1,0000000000000000000000000000000000000000..f11330a8916d4adf2ba241ef4495ef772d8fcdf0
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- #![allow(clippy::almost_complete_letter_range)]
 +// run-rustfix
 +// edition:2018
 +
 +#![warn(clippy::needless_parens_on_range_literals)]
++#![allow(clippy::almost_complete_range)]
 +
 +fn main() {
 +    let _ = 'a'..='z';
 +    let _ = 'a'..'z';
 +    let _ = (1.)..2.;
 +    let _ = (1.)..2.;
 +    let _ = 'a'..;
 +    let _ = ..'z';
 +}
index 7abb8a1adc1bcc4f0178599adc3391c748f73f5b,0000000000000000000000000000000000000000..671c0009e23b7d5b60d8f70f3b6abd5a94dc79cf
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- #![allow(clippy::almost_complete_letter_range)]
 +// run-rustfix
 +// edition:2018
 +
 +#![warn(clippy::needless_parens_on_range_literals)]
++#![allow(clippy::almost_complete_range)]
 +
 +fn main() {
 +    let _ = ('a')..=('z');
 +    let _ = 'a'..('z');
 +    let _ = (1.)..2.;
 +    let _ = (1.)..(2.);
 +    let _ = ('a')..;
 +    let _ = ..('z');
 +}
index f69982d63a898d17ba3b9f6ff417c42ea8442bd8,0000000000000000000000000000000000000000..beec42f08bb05666df617799cc1b4068abfcdb75
mode 100644,000000..100644
--- /dev/null
@@@ -1,402 -1,0 +1,425 @@@
++#![feature(type_alias_impl_trait)]
 +#![warn(clippy::new_ret_no_self)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +trait R {
 +    type Item;
 +}
 +
 +trait Q {
 +    type Item;
 +    type Item2;
 +}
 +
 +struct S;
 +
 +impl R for S {
 +    type Item = Self;
 +}
 +
 +impl S {
 +    // should not trigger the lint
 +    pub fn new() -> impl R<Item = Self> {
 +        S
 +    }
 +}
 +
 +struct S2;
 +
 +impl R for S2 {
 +    type Item = Self;
 +}
 +
 +impl S2 {
 +    // should not trigger the lint
 +    pub fn new(_: String) -> impl R<Item = Self> {
 +        S2
 +    }
 +}
 +
 +struct S3;
 +
 +impl R for S3 {
 +    type Item = u32;
 +}
 +
 +impl S3 {
 +    // should trigger the lint
 +    pub fn new(_: String) -> impl R<Item = u32> {
 +        S3
 +    }
 +}
 +
 +struct S4;
 +
 +impl Q for S4 {
 +    type Item = u32;
 +    type Item2 = Self;
 +}
 +
 +impl S4 {
 +    // should not trigger the lint
 +    pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
 +        S4
 +    }
 +}
 +
 +struct T;
 +
 +impl T {
 +    // should not trigger lint
 +    pub fn new() -> Self {
 +        unimplemented!();
 +    }
 +}
 +
 +struct U;
 +
 +impl U {
 +    // should trigger lint
 +    pub fn new() -> u32 {
 +        unimplemented!();
 +    }
 +}
 +
 +struct V;
 +
 +impl V {
 +    // should trigger lint
 +    pub fn new(_: String) -> u32 {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk;
 +
 +impl TupleReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> (Self, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk2;
 +
 +impl TupleReturnerOk2 {
 +    // should not trigger lint (it doesn't matter which element in the tuple is Self)
 +    pub fn new() -> (u32, Self) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk3;
 +
 +impl TupleReturnerOk3 {
 +    // should not trigger lint (tuple can contain multiple Self)
 +    pub fn new() -> (Self, Self) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerBad;
 +
 +impl TupleReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> (u32, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct MutPointerReturnerOk;
 +
 +impl MutPointerReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> *mut Self {
 +        unimplemented!();
 +    }
 +}
 +
 +struct ConstPointerReturnerOk2;
 +
 +impl ConstPointerReturnerOk2 {
 +    // should not trigger lint
 +    pub fn new() -> *const Self {
 +        unimplemented!();
 +    }
 +}
 +
 +struct MutPointerReturnerBad;
 +
 +impl MutPointerReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> *mut V {
 +        unimplemented!();
 +    }
 +}
 +
 +struct GenericReturnerOk;
 +
 +impl GenericReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> Option<Self> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct GenericReturnerBad;
 +
 +impl GenericReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> Option<u32> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk;
 +
 +impl NestedReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> (Option<Self>, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk2;
 +
 +impl NestedReturnerOk2 {
 +    // should not trigger lint
 +    pub fn new() -> ((Self, u32), u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk3;
 +
 +impl NestedReturnerOk3 {
 +    // should not trigger lint
 +    pub fn new() -> Option<(Self, u32)> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct WithLifetime<'a> {
 +    cat: &'a str,
 +}
 +
 +impl<'a> WithLifetime<'a> {
 +    // should not trigger the lint, because the lifetimes are different
 +    pub fn new<'b: 'a>(s: &'b str) -> WithLifetime<'b> {
 +        unimplemented!();
 +    }
 +}
 +
 +mod issue5435 {
 +    struct V;
 +
 +    pub trait TraitRetSelf {
 +        // should not trigger lint
 +        fn new() -> Self;
 +    }
 +
 +    pub trait TraitRet {
 +        // should trigger lint as we are in trait definition
 +        fn new() -> String;
 +    }
 +    pub struct StructRet;
 +    impl TraitRet for StructRet {
 +        // should not trigger lint as we are in the impl block
 +        fn new() -> String {
 +            unimplemented!();
 +        }
 +    }
 +
 +    pub trait TraitRet2 {
 +        // should trigger lint
 +        fn new(_: String) -> String;
 +    }
 +
 +    trait TupleReturnerOk {
 +        // should not trigger lint
 +        fn new() -> (Self, u32)
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait TupleReturnerOk2 {
 +        // should not trigger lint (it doesn't matter which element in the tuple is Self)
 +        fn new() -> (u32, Self)
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait TupleReturnerOk3 {
 +        // should not trigger lint (tuple can contain multiple Self)
 +        fn new() -> (Self, Self)
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait TupleReturnerBad {
 +        // should trigger lint
 +        fn new() -> (u32, u32) {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait MutPointerReturnerOk {
 +        // should not trigger lint
 +        fn new() -> *mut Self
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait ConstPointerReturnerOk2 {
 +        // should not trigger lint
 +        fn new() -> *const Self
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait MutPointerReturnerBad {
 +        // should trigger lint
 +        fn new() -> *mut V {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait GenericReturnerOk {
 +        // should not trigger lint
 +        fn new() -> Option<Self>
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait NestedReturnerOk {
 +        // should not trigger lint
 +        fn new() -> (Option<Self>, u32)
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait NestedReturnerOk2 {
 +        // should not trigger lint
 +        fn new() -> ((Self, u32), u32)
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +
 +    trait NestedReturnerOk3 {
 +        // should not trigger lint
 +        fn new() -> Option<(Self, u32)>
 +        where
 +            Self: Sized,
 +        {
 +            unimplemented!();
 +        }
 +    }
 +}
 +
 +// issue #1724
 +struct RetOtherSelf<T>(T);
 +struct RetOtherSelfWrapper<T>(T);
 +
 +impl RetOtherSelf<T> {
 +    fn new(t: T) -> RetOtherSelf<RetOtherSelfWrapper<T>> {
 +        RetOtherSelf(RetOtherSelfWrapper(t))
 +    }
 +}
 +
 +mod issue7344 {
 +    struct RetImplTraitSelf<T>(T);
 +
 +    impl<T> RetImplTraitSelf<T> {
 +        // should not trigger lint
 +        fn new(t: T) -> impl Into<Self> {
 +            Self(t)
 +        }
 +    }
 +
 +    struct RetImplTraitNoSelf<T>(T);
 +
 +    impl<T> RetImplTraitNoSelf<T> {
 +        // should trigger lint
 +        fn new(t: T) -> impl Into<i32> {
 +            1
 +        }
 +    }
 +
 +    trait Trait2<T, U> {}
 +    impl<T, U> Trait2<T, U> for () {}
 +
 +    struct RetImplTraitSelf2<T>(T);
 +
 +    impl<T> RetImplTraitSelf2<T> {
 +        // should not trigger lint
 +        fn new(t: T) -> impl Trait2<(), Self> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    struct RetImplTraitNoSelf2<T>(T);
 +
 +    impl<T> RetImplTraitNoSelf2<T> {
 +        // should trigger lint
 +        fn new(t: T) -> impl Trait2<(), i32> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    struct RetImplTraitSelfAdt<'a>(&'a str);
 +
 +    impl<'a> RetImplTraitSelfAdt<'a> {
 +        // should not trigger lint
 +        fn new<'b: 'a>(s: &'b str) -> impl Into<RetImplTraitSelfAdt<'b>> {
 +            RetImplTraitSelfAdt(s)
 +        }
 +    }
 +}
++
++mod issue10041 {
++    struct Bomb;
++
++    impl Bomb {
++        // Hidden <Rhs = Self> default generic paramter.
++        pub fn new() -> impl PartialOrd {
++            0i32
++        }
++    }
++
++    // TAIT with self-referencing bounds
++    type X = impl std::ops::Add<Output = X>;
++
++    struct Bomb2;
++
++    impl Bomb2 {
++        pub fn new() -> X {
++            0i32
++        }
++    }
++}
index bc13be47927b1c3fa37a75795a316f5c521319ac,0000000000000000000000000000000000000000..2eaebfb5cac50041df6bc18f6c2a78bb79017691
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,112 @@@
-   --> $DIR/new_ret_no_self.rs:49:5
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:81:5
++  --> $DIR/new_ret_no_self.rs:50:5
 +   |
 +LL | /     pub fn new(_: String) -> impl R<Item = u32> {
 +LL | |         S3
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:90:5
++  --> $DIR/new_ret_no_self.rs:82:5
 +   |
 +LL | /     pub fn new() -> u32 {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:126:5
++  --> $DIR/new_ret_no_self.rs:91:5
 +   |
 +LL | /     pub fn new(_: String) -> u32 {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:153:5
++  --> $DIR/new_ret_no_self.rs:127:5
 +   |
 +LL | /     pub fn new() -> (u32, u32) {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:171:5
++  --> $DIR/new_ret_no_self.rs:154:5
 +   |
 +LL | /     pub fn new() -> *mut V {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:224:9
++  --> $DIR/new_ret_no_self.rs:172:5
 +   |
 +LL | /     pub fn new() -> Option<u32> {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:236:9
++  --> $DIR/new_ret_no_self.rs:225:9
 +   |
 +LL |         fn new() -> String;
 +   |         ^^^^^^^^^^^^^^^^^^^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:271:9
++  --> $DIR/new_ret_no_self.rs:237:9
 +   |
 +LL |         fn new(_: String) -> String;
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:298:9
++  --> $DIR/new_ret_no_self.rs:272:9
 +   |
 +LL | /         fn new() -> (u32, u32) {
 +LL | |             unimplemented!();
 +LL | |         }
 +   | |_________^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:368:9
++  --> $DIR/new_ret_no_self.rs:299:9
 +   |
 +LL | /         fn new() -> *mut V {
 +LL | |             unimplemented!();
 +LL | |         }
 +   | |_________^
 +
 +error: methods called `new` usually return `Self`
-   --> $DIR/new_ret_no_self.rs:389:9
++  --> $DIR/new_ret_no_self.rs:369:9
 +   |
 +LL | /         fn new(t: T) -> impl Into<i32> {
 +LL | |             1
 +LL | |         }
 +   | |_________^
 +
 +error: methods called `new` usually return `Self`
- error: aborting due to 12 previous errors
++  --> $DIR/new_ret_no_self.rs:390:9
 +   |
 +LL | /         fn new(t: T) -> impl Trait2<(), i32> {
 +LL | |             unimplemented!()
 +LL | |         }
 +   | |_________^
 +
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:410:9
++   |
++LL | /         pub fn new() -> impl PartialOrd {
++LL | |             0i32
++LL | |         }
++   | |_________^
++
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:421:9
++   |
++LL | /         pub fn new() -> X {
++LL | |             0i32
++LL | |         }
++   | |_________^
++
++error: aborting due to 14 previous errors
 +
index 4c5846fe837eaa8a68ed10ad585271923f0f6588,0000000000000000000000000000000000000000..bca777a890c3b249c2f0ae7bbf61c099a2d0705e
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,72 @@@
 +// run-rustfix
 +
 +#![allow(unused)]
 +
 +#[derive(Debug)]
 +struct Foo;
 +
 +const VAR_ONE: &str = "Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
 +
 +const VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +
 +const VAR_SIX: &u8 = &5;
 +
 +const VAR_HEIGHT: &Foo = &Foo {};
 +
 +const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
 +
 +static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +static STATIC_VAR_SIX: &u8 = &5;
 +
 +static STATIC_VAR_HEIGHT: &Foo = &Foo {};
 +
 +static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
++static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0];
++
 +fn main() {
 +    let false_positive: &'static str = "test";
++
++    unsafe {
++        STATIC_MUT_SLICE[0] = 0;
++    }
 +}
 +
 +trait Bar {
 +    const TRAIT_VAR: &'static str;
 +}
 +
 +impl Foo {
 +    const IMPL_VAR: &'static str = "var";
 +}
 +
 +impl Bar for Foo {
 +    const TRAIT_VAR: &'static str = "foo";
 +}
 +
 +#[clippy::msrv = "1.16"]
 +fn msrv_1_16() {
 +    static V: &'static u8 = &16;
 +}
 +
 +#[clippy::msrv = "1.17"]
 +fn msrv_1_17() {
 +    static V: &u8 = &17;
 +}
index 64a66be1a83c753ff8a786167759fd4f04ea52ef,0000000000000000000000000000000000000000..afe7644816d2e4f0420d04d1547c3080f45d984b
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,72 @@@
 +// run-rustfix
 +
 +#![allow(unused)]
 +
 +#[derive(Debug)]
 +struct Foo;
 +
 +const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
 +
 +const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +
 +const VAR_SIX: &'static u8 = &5;
 +
 +const VAR_HEIGHT: &'static Foo = &Foo {};
 +
 +const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
 +
 +static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +static STATIC_VAR_SIX: &'static u8 = &5;
 +
 +static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
 +
 +static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
++static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
++
 +fn main() {
 +    let false_positive: &'static str = "test";
++
++    unsafe {
++        STATIC_MUT_SLICE[0] = 0;
++    }
 +}
 +
 +trait Bar {
 +    const TRAIT_VAR: &'static str;
 +}
 +
 +impl Foo {
 +    const IMPL_VAR: &'static str = "var";
 +}
 +
 +impl Bar for Foo {
 +    const TRAIT_VAR: &'static str = "foo";
 +}
 +
 +#[clippy::msrv = "1.16"]
 +fn msrv_1_16() {
 +    static V: &'static u8 = &16;
 +}
 +
 +#[clippy::msrv = "1.17"]
 +fn msrv_1_17() {
 +    static V: &'static u8 = &17;
 +}
index 0938ebf783ff16888852e0be386dc22c86f1c254,0000000000000000000000000000000000000000..b2cbd2d9d01b0350e7f31710c9fdec05f2cfc6ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,112 @@@
-   --> $DIR/redundant_static_lifetimes.rs:65:16
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:8:17
 +   |
 +LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
 +   |                -^^^^^^^---- help: consider removing `'static`: `&str`
 +   |
 +   = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:12:21
 +   |
 +LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +   |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:14:32
 +   |
 +LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +   |                               -^^^^^^^---- help: consider removing `'static`: `&str`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:14:47
 +   |
 +LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +   |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:16:17
 +   |
 +LL | const VAR_SIX: &'static u8 = &5;
 +   |                -^^^^^^^--- help: consider removing `'static`: `&u8`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:18:20
 +   |
 +LL | const VAR_HEIGHT: &'static Foo = &Foo {};
 +   |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:20:19
 +   |
 +LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
 +   |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:22:19
 +   |
 +LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +   |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 +
 +error: constants have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:24:19
 +   |
 +LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +   |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:26:25
 +   |
 +LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
 +   |                        -^^^^^^^---- help: consider removing `'static`: `&str`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:30:29
 +   |
 +LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +   |                            -^^^^^^^---- help: consider removing `'static`: `&str`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:32:25
 +   |
 +LL | static STATIC_VAR_SIX: &'static u8 = &5;
 +   |                        -^^^^^^^--- help: consider removing `'static`: `&u8`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:34:28
 +   |
 +LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
 +   |                           -^^^^^^^---- help: consider removing `'static`: `&Foo`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:36:27
 +   |
 +LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
 +   |                          -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:38:27
 +   |
 +LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +   |                          -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 +
 +error: statics have by default a `'static` lifetime
 +  --> $DIR/redundant_static_lifetimes.rs:40:27
 +   |
 +LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +   |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 +
 +error: statics have by default a `'static` lifetime
- error: aborting due to 17 previous errors
++  --> $DIR/redundant_static_lifetimes.rs:42:31
++   |
++LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
++   |                              -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]`
++
++error: statics have by default a `'static` lifetime
++  --> $DIR/redundant_static_lifetimes.rs:71:16
 +   |
 +LL |     static V: &'static u8 = &17;
 +   |               -^^^^^^^--- help: consider removing `'static`: `&u8`
 +
++error: aborting due to 18 previous errors
 +
index 689928f0479468fb8c0305b11d1299e01fd4f4ca,0000000000000000000000000000000000000000..2f76b57529607a14ed3165dea40c3ddf0dd9975d
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,83 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +// run-rustfix
 +
++#![allow(clippy::almost_complete_range)]
 +#![allow(clippy::disallowed_names)]
 +#![allow(clippy::blocks_in_if_conditions)]
 +#![allow(clippy::box_collection)]
 +#![allow(clippy::redundant_static_lifetimes)]
 +#![allow(clippy::cognitive_complexity)]
 +#![allow(clippy::disallowed_methods)]
 +#![allow(clippy::disallowed_types)]
 +#![allow(clippy::mixed_read_write_in_expression)]
 +#![allow(clippy::useless_conversion)]
 +#![allow(clippy::match_result_ok)]
 +#![allow(clippy::overly_complex_bool_expr)]
 +#![allow(clippy::new_without_default)]
 +#![allow(clippy::bind_instead_of_map)]
 +#![allow(clippy::expect_used)]
 +#![allow(clippy::map_unwrap_or)]
 +#![allow(clippy::unwrap_used)]
 +#![allow(clippy::needless_borrow)]
 +#![allow(clippy::single_char_add_str)]
 +#![allow(clippy::module_name_repetitions)]
 +#![allow(clippy::recursive_format_impl)]
 +#![allow(clippy::invisible_characters)]
 +#![allow(drop_bounds)]
 +#![allow(for_loops_over_fallibles)]
 +#![allow(array_into_iter)]
 +#![allow(invalid_atomic_ordering)]
 +#![allow(invalid_value)]
 +#![allow(let_underscore_drop)]
 +#![allow(enum_intrinsics_non_enums)]
 +#![allow(non_fmt_panics)]
 +#![allow(named_arguments_used_positionally)]
 +#![allow(temporary_cstring_as_ptr)]
 +#![allow(unknown_lints)]
 +#![allow(unused_labels)]
++#![warn(clippy::almost_complete_range)]
 +#![warn(clippy::disallowed_names)]
 +#![warn(clippy::blocks_in_if_conditions)]
 +#![warn(clippy::blocks_in_if_conditions)]
 +#![warn(clippy::box_collection)]
 +#![warn(clippy::redundant_static_lifetimes)]
 +#![warn(clippy::cognitive_complexity)]
 +#![warn(clippy::disallowed_methods)]
 +#![warn(clippy::disallowed_types)]
 +#![warn(clippy::mixed_read_write_in_expression)]
 +#![warn(clippy::useless_conversion)]
 +#![warn(clippy::match_result_ok)]
 +#![warn(clippy::overly_complex_bool_expr)]
 +#![warn(clippy::new_without_default)]
 +#![warn(clippy::bind_instead_of_map)]
 +#![warn(clippy::expect_used)]
 +#![warn(clippy::map_unwrap_or)]
 +#![warn(clippy::map_unwrap_or)]
 +#![warn(clippy::unwrap_used)]
 +#![warn(clippy::needless_borrow)]
 +#![warn(clippy::expect_used)]
 +#![warn(clippy::map_unwrap_or)]
 +#![warn(clippy::unwrap_used)]
 +#![warn(clippy::single_char_add_str)]
 +#![warn(clippy::module_name_repetitions)]
 +#![warn(clippy::recursive_format_impl)]
 +#![warn(clippy::invisible_characters)]
 +#![warn(drop_bounds)]
 +#![warn(for_loops_over_fallibles)]
 +#![warn(for_loops_over_fallibles)]
 +#![warn(for_loops_over_fallibles)]
 +#![warn(array_into_iter)]
 +#![warn(invalid_atomic_ordering)]
 +#![warn(invalid_value)]
 +#![warn(let_underscore_drop)]
 +#![warn(enum_intrinsics_non_enums)]
 +#![warn(non_fmt_panics)]
 +#![warn(named_arguments_used_positionally)]
 +#![warn(temporary_cstring_as_ptr)]
 +#![warn(unknown_lints)]
 +#![warn(unused_labels)]
 +
 +fn main() {}
index b74aa650ffd475946adc1f595d0e2d21b4d0fa15,0000000000000000000000000000000000000000..699c0ff464e9fb247989fd0b559c8a35576b63f4
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,83 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +// run-rustfix
 +
++#![allow(clippy::almost_complete_range)]
 +#![allow(clippy::disallowed_names)]
 +#![allow(clippy::blocks_in_if_conditions)]
 +#![allow(clippy::box_collection)]
 +#![allow(clippy::redundant_static_lifetimes)]
 +#![allow(clippy::cognitive_complexity)]
 +#![allow(clippy::disallowed_methods)]
 +#![allow(clippy::disallowed_types)]
 +#![allow(clippy::mixed_read_write_in_expression)]
 +#![allow(clippy::useless_conversion)]
 +#![allow(clippy::match_result_ok)]
 +#![allow(clippy::overly_complex_bool_expr)]
 +#![allow(clippy::new_without_default)]
 +#![allow(clippy::bind_instead_of_map)]
 +#![allow(clippy::expect_used)]
 +#![allow(clippy::map_unwrap_or)]
 +#![allow(clippy::unwrap_used)]
 +#![allow(clippy::needless_borrow)]
 +#![allow(clippy::single_char_add_str)]
 +#![allow(clippy::module_name_repetitions)]
 +#![allow(clippy::recursive_format_impl)]
 +#![allow(clippy::invisible_characters)]
 +#![allow(drop_bounds)]
 +#![allow(for_loops_over_fallibles)]
 +#![allow(array_into_iter)]
 +#![allow(invalid_atomic_ordering)]
 +#![allow(invalid_value)]
 +#![allow(let_underscore_drop)]
 +#![allow(enum_intrinsics_non_enums)]
 +#![allow(non_fmt_panics)]
 +#![allow(named_arguments_used_positionally)]
 +#![allow(temporary_cstring_as_ptr)]
 +#![allow(unknown_lints)]
 +#![allow(unused_labels)]
++#![warn(clippy::almost_complete_letter_range)]
 +#![warn(clippy::blacklisted_name)]
 +#![warn(clippy::block_in_if_condition_expr)]
 +#![warn(clippy::block_in_if_condition_stmt)]
 +#![warn(clippy::box_vec)]
 +#![warn(clippy::const_static_lifetime)]
 +#![warn(clippy::cyclomatic_complexity)]
 +#![warn(clippy::disallowed_method)]
 +#![warn(clippy::disallowed_type)]
 +#![warn(clippy::eval_order_dependence)]
 +#![warn(clippy::identity_conversion)]
 +#![warn(clippy::if_let_some_result)]
 +#![warn(clippy::logic_bug)]
 +#![warn(clippy::new_without_default_derive)]
 +#![warn(clippy::option_and_then_some)]
 +#![warn(clippy::option_expect_used)]
 +#![warn(clippy::option_map_unwrap_or)]
 +#![warn(clippy::option_map_unwrap_or_else)]
 +#![warn(clippy::option_unwrap_used)]
 +#![warn(clippy::ref_in_deref)]
 +#![warn(clippy::result_expect_used)]
 +#![warn(clippy::result_map_unwrap_or_else)]
 +#![warn(clippy::result_unwrap_used)]
 +#![warn(clippy::single_char_push_str)]
 +#![warn(clippy::stutter)]
 +#![warn(clippy::to_string_in_display)]
 +#![warn(clippy::zero_width_space)]
 +#![warn(clippy::drop_bounds)]
 +#![warn(clippy::for_loop_over_option)]
 +#![warn(clippy::for_loop_over_result)]
 +#![warn(clippy::for_loops_over_fallibles)]
 +#![warn(clippy::into_iter_on_array)]
 +#![warn(clippy::invalid_atomic_ordering)]
 +#![warn(clippy::invalid_ref)]
 +#![warn(clippy::let_underscore_drop)]
 +#![warn(clippy::mem_discriminant_non_enum)]
 +#![warn(clippy::panic_params)]
 +#![warn(clippy::positional_named_format_parameters)]
 +#![warn(clippy::temporary_cstring_as_ptr)]
 +#![warn(clippy::unknown_clippy_lints)]
 +#![warn(clippy::unused_label)]
 +
 +fn main() {}
index 622a32c5908aeaa3689041a42a6fa6e6f8920be7,0000000000000000000000000000000000000000..9af58dc75a68f41daff7f88a050856295b19ec29
mode 100644,000000..100644
--- /dev/null
@@@ -1,244 -1,0 +1,250 @@@
-   --> $DIR/rename.rs:40:9
++error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
++  --> $DIR/rename.rs:41:9
++   |
++LL | #![warn(clippy::almost_complete_letter_range)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
++   |
++   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
++
 +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-    |
-    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
++  --> $DIR/rename.rs:42:9
 +   |
 +LL | #![warn(clippy::blacklisted_name)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
-   --> $DIR/rename.rs:41:9
 +
 +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-   --> $DIR/rename.rs:42:9
++  --> $DIR/rename.rs:43: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:43:9
++  --> $DIR/rename.rs:44: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:44:9
++  --> $DIR/rename.rs:45: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:45:9
++  --> $DIR/rename.rs:46: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:46:9
++  --> $DIR/rename.rs:47:9
 +   |
 +LL | #![warn(clippy::cyclomatic_complexity)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 +
 +error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-   --> $DIR/rename.rs:47:9
++  --> $DIR/rename.rs:48: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:48:9
++  --> $DIR/rename.rs:49: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:49:9
++  --> $DIR/rename.rs:50: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:50:9
++  --> $DIR/rename.rs:51: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:51:9
++  --> $DIR/rename.rs:52:9
 +   |
 +LL | #![warn(clippy::if_let_some_result)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 +
 +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-   --> $DIR/rename.rs:52:9
++  --> $DIR/rename.rs:53: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:53:9
++  --> $DIR/rename.rs:54: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:54:9
++  --> $DIR/rename.rs:55: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:55:9
++  --> $DIR/rename.rs:56: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:56:9
++  --> $DIR/rename.rs:57: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:57:9
++  --> $DIR/rename.rs:58: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:58:9
++  --> $DIR/rename.rs:59: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:59:9
++  --> $DIR/rename.rs:60: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:60:9
++  --> $DIR/rename.rs:61: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:61:9
++  --> $DIR/rename.rs:62: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:62:9
++  --> $DIR/rename.rs:63: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:63:9
++  --> $DIR/rename.rs:64: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:64:9
++  --> $DIR/rename.rs:65: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:65:9
++  --> $DIR/rename.rs:66: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:66:9
++  --> $DIR/rename.rs:67:9
 +   |
 +LL | #![warn(clippy::zero_width_space)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 +
 +error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-   --> $DIR/rename.rs:67:9
++  --> $DIR/rename.rs:68:9
 +   |
 +LL | #![warn(clippy::drop_bounds)]
 +   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 +
 +error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-   --> $DIR/rename.rs:68:9
++  --> $DIR/rename.rs:69: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:69:9
++  --> $DIR/rename.rs:70: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:70:9
++  --> $DIR/rename.rs:71:9
 +   |
 +LL | #![warn(clippy::for_loops_over_fallibles)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 +
 +error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-   --> $DIR/rename.rs:71:9
++  --> $DIR/rename.rs:72: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:72:9
++  --> $DIR/rename.rs:73: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:73:9
++  --> $DIR/rename.rs:74: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:74:9
++  --> $DIR/rename.rs:75: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:75:9
++  --> $DIR/rename.rs:76: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:76:9
++  --> $DIR/rename.rs:77: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:77:9
++  --> $DIR/rename.rs:78: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:78:9
++  --> $DIR/rename.rs:79: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:79:9
++  --> $DIR/rename.rs:80: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`
- error: aborting due to 40 previous errors
++  --> $DIR/rename.rs:81:9
 +   |
 +LL | #![warn(clippy::unused_label)]
 +   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 +
++error: aborting due to 41 previous errors
 +
index 9d0d1124c460ed45b1b5894bd3878b18d15def72,0000000000000000000000000000000000000000..713cff604a1d7d6028c367f5efcf2e4c2de552fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,134 -1,0 +1,140 @@@
 +// run-rustfix
 +#![allow(unused)]
 +#![warn(clippy::seek_to_start_instead_of_rewind)]
 +
 +use std::fs::OpenOptions;
 +use std::io::{Read, Seek, SeekFrom, Write};
 +
 +struct StructWithSeekMethod {}
 +
 +impl StructWithSeekMethod {
 +    fn seek(&mut self, from: SeekFrom) {}
 +}
 +
 +trait MySeekTrait {
 +    fn seek(&mut self, from: SeekFrom) {}
 +}
 +
 +struct StructWithSeekTrait {}
 +impl MySeekTrait for StructWithSeekTrait {}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait_bound<T: MySeekTrait>(t: &mut T) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should trigger clippy warning
 +fn seek_to_start<T: Seek>(t: &mut T) {
 +    t.rewind();
 +}
 +
 +// This should trigger clippy warning
 +fn owned_seek_to_start<T: Seek>(mut t: T) {
 +    t.rewind();
 +}
 +
 +// This should NOT trigger clippy warning because
 +// it does not seek to start
 +fn seek_to_5<T: Seek>(t: &mut T) {
 +    t.seek(SeekFrom::Start(5));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// it does not seek to start
 +fn seek_to_end<T: Seek>(t: &mut T) {
 +    t.seek(SeekFrom::End(0));
 +}
 +
++// This should NOT trigger clippy warning because
++// expr is used here
++fn seek_to_start_in_let<T: Seek>(t: &mut T) {
++    let a = t.seek(SeekFrom::Start(0)).unwrap();
++}
++
 +fn main() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let mut my_struct_trait = StructWithSeekTrait {};
 +    seek_to_start_false_trait_bound(&mut my_struct_trait);
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +    seek_to_5(&mut f);
 +    seek_to_end(&mut f);
 +    seek_to_start(&mut f);
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
 +
 +#[clippy::msrv = "1.54"]
 +fn msrv_1_54() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +
 +    f.seek(SeekFrom::Start(0));
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
 +
 +#[clippy::msrv = "1.55"]
 +fn msrv_1_55() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +
 +    f.rewind();
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
index c5bc57cc3a74ce617a96b4dd401a58cca895647b,0000000000000000000000000000000000000000..467003a1a66f684141d3e8be6bc500d3acb99d66
mode 100644,000000..100644
--- /dev/null
@@@ -1,134 -1,0 +1,140 @@@
 +// run-rustfix
 +#![allow(unused)]
 +#![warn(clippy::seek_to_start_instead_of_rewind)]
 +
 +use std::fs::OpenOptions;
 +use std::io::{Read, Seek, SeekFrom, Write};
 +
 +struct StructWithSeekMethod {}
 +
 +impl StructWithSeekMethod {
 +    fn seek(&mut self, from: SeekFrom) {}
 +}
 +
 +trait MySeekTrait {
 +    fn seek(&mut self, from: SeekFrom) {}
 +}
 +
 +struct StructWithSeekTrait {}
 +impl MySeekTrait for StructWithSeekTrait {}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// StructWithSeekMethod does not implement std::io::Seek;
 +fn seek_to_start_false_trait_bound<T: MySeekTrait>(t: &mut T) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should trigger clippy warning
 +fn seek_to_start<T: Seek>(t: &mut T) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should trigger clippy warning
 +fn owned_seek_to_start<T: Seek>(mut t: T) {
 +    t.seek(SeekFrom::Start(0));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// it does not seek to start
 +fn seek_to_5<T: Seek>(t: &mut T) {
 +    t.seek(SeekFrom::Start(5));
 +}
 +
 +// This should NOT trigger clippy warning because
 +// it does not seek to start
 +fn seek_to_end<T: Seek>(t: &mut T) {
 +    t.seek(SeekFrom::End(0));
 +}
 +
++// This should NOT trigger clippy warning because
++// expr is used here
++fn seek_to_start_in_let<T: Seek>(t: &mut T) {
++    let a = t.seek(SeekFrom::Start(0)).unwrap();
++}
++
 +fn main() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let mut my_struct_trait = StructWithSeekTrait {};
 +    seek_to_start_false_trait_bound(&mut my_struct_trait);
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +    seek_to_5(&mut f);
 +    seek_to_end(&mut f);
 +    seek_to_start(&mut f);
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
 +
 +#[clippy::msrv = "1.54"]
 +fn msrv_1_54() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +
 +    f.seek(SeekFrom::Start(0));
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
 +
 +#[clippy::msrv = "1.55"]
 +fn msrv_1_55() {
 +    let mut f = OpenOptions::new()
 +        .write(true)
 +        .read(true)
 +        .create(true)
 +        .open("foo.txt")
 +        .unwrap();
 +
 +    let hello = "Hello!\n";
 +    write!(f, "{hello}").unwrap();
 +
 +    f.seek(SeekFrom::Start(0));
 +
 +    let mut buf = String::new();
 +    f.read_to_string(&mut buf).unwrap();
 +
 +    assert_eq!(&buf, hello);
 +}
index 6cce025359fe2918bce42ea6bdbef601d8c74948,0000000000000000000000000000000000000000..342ec00fe7295ad8ec3afd061f1af4dbbc48110c
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,22 @@@
-   --> $DIR/seek_to_start_instead_of_rewind.rs:128:7
 +error: used `seek` to go to the start of the stream
 +  --> $DIR/seek_to_start_instead_of_rewind.rs:53:7
 +   |
 +LL |     t.seek(SeekFrom::Start(0));
 +   |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 +   |
 +   = note: `-D clippy::seek-to-start-instead-of-rewind` implied by `-D warnings`
 +
 +error: used `seek` to go to the start of the stream
 +  --> $DIR/seek_to_start_instead_of_rewind.rs:58:7
 +   |
 +LL |     t.seek(SeekFrom::Start(0));
 +   |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 +
 +error: used `seek` to go to the start of the stream
++  --> $DIR/seek_to_start_instead_of_rewind.rs:134:7
 +   |
 +LL |     f.seek(SeekFrom::Start(0));
 +   |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 +
 +error: aborting due to 3 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..42e97e1ca358e145bd51d8d464dfd77d365d3069
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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()
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f40848f702e1cbabd76a1a55c26fde7425a90f6b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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()
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..48d3690e2bdee5bf1e2face8a3e255ae111bf5bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,54 @@@
++error: consider moving the `;` inside the block for consistent formatting
++  --> $DIR/semicolon_inside_block.rs:39:5
++   |
++LL |     { unit_fn_block() };
++   |     ^^^^^^^^^^^^^^^^^^^^
++   |
++   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
++help: put the `;` here
++   |
++LL -     { unit_fn_block() };
++LL +     { unit_fn_block(); }
++   |
++
++error: consider moving the `;` inside the block for consistent formatting
++  --> $DIR/semicolon_inside_block.rs:40: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/semicolon_inside_block.rs:48:5
++   |
++LL | /     {
++LL | |         unit_fn_block();
++LL | |         unit_fn_block()
++LL | |     };
++   | |______^
++   |
++help: put the `;` here
++   |
++LL ~         unit_fn_block();
++LL ~     }
++   |
++
++error: consider moving the `;` inside the block for consistent formatting
++  --> $DIR/semicolon_inside_block.rs:61:5
++   |
++LL |     { m!(()) };
++   |     ^^^^^^^^^^^
++   |
++help: put the `;` here
++   |
++LL -     { m!(()) };
++LL +     { m!(()); }
++   |
++
++error: aborting due to 4 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..091eaa7518e95d1750a3c1fc59ecd27479c7835a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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()
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ce46431fac9ace2c0c4221bb32348a7c866f1b7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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()
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dcc102e60994a6fea104d330e799328b33e0ecd6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,54 @@@
++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:52:5
++   |
++LL | /     {
++LL | |         unit_fn_block();
++LL | |         unit_fn_block();
++LL | |     }
++   | |_____^
++   |
++help: put the `;` here
++   |
++LL ~         unit_fn_block()
++LL ~     };
++   |
++
++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 4 previous errors
++
index df2256e4f97de98afe0285e587ac9924c000fb3a,0000000000000000000000000000000000000000..506187fc125736f778df20459bfd641c4350901a
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,36 @@@
 +// run-rustfix
 +
 +#![allow(dead_code, unused_variables)]
 +#![warn(clippy::string_lit_as_bytes)]
 +
 +fn str_lit_as_bytes() {
 +    let bs = b"hello there";
 +
 +    let bs = br###"raw string with 3# plus " ""###;
 +
 +    let bs = b"lit to string".to_vec();
 +    let bs = b"lit to owned".to_vec();
 +
 +    // 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();
 +
 +    let ubs = "☃".to_string().into_bytes();
 +    let ubs = "this is also too long and shouldn't be fixed".to_string().into_bytes();
 +
 +    let strify = stringify!(foobar).as_bytes();
 +
 +    let current_version = env!("CARGO_PKG_VERSION").as_bytes();
 +
 +    let includestr = include_bytes!("string_lit_as_bytes.rs");
 +
 +    let _ = b"string with newline\t\n";
++
++    let _ = match "x".as_bytes() {
++        b"xx" => 0,
++        [b'x', ..] => 1,
++        _ => 2,
++    };
 +}
 +
 +fn main() {}
index c6bf8f732ed9f615d1ea2d660d6ed7602513270b,0000000000000000000000000000000000000000..2c339f1ddb819334b446e0007f6c5e6146965f29
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,36 @@@
 +// run-rustfix
 +
 +#![allow(dead_code, unused_variables)]
 +#![warn(clippy::string_lit_as_bytes)]
 +
 +fn str_lit_as_bytes() {
 +    let bs = "hello there".as_bytes();
 +
 +    let bs = r###"raw string with 3# plus " ""###.as_bytes();
 +
 +    let bs = "lit to string".to_string().into_bytes();
 +    let bs = "lit to owned".to_owned().into_bytes();
 +
 +    // 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();
 +
 +    let ubs = "☃".to_string().into_bytes();
 +    let ubs = "this is also too long and shouldn't be fixed".to_string().into_bytes();
 +
 +    let strify = stringify!(foobar).as_bytes();
 +
 +    let current_version = env!("CARGO_PKG_VERSION").as_bytes();
 +
 +    let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
 +
 +    let _ = "string with newline\t\n".as_bytes();
++
++    let _ = match "x".as_bytes() {
++        b"xx" => 0,
++        [b'x', ..] => 1,
++        _ => 2,
++    };
 +}
 +
 +fn main() {}
index 96cc0877960ec00c627a896f5eb54cafc633f2c1,0000000000000000000000000000000000000000..52b5343c351e6e42365e484869c1b4dd4160c996
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,32 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::uninlined_format_args)]
 +
 +fn main() {
 +    let var = 1;
 +
 +    println!("val='{var}'");
 +
 +    if var > 0 {
 +        panic!("p1 {}", var);
 +    }
 +    if var > 0 {
 +        panic!("p2 {0}", var);
 +    }
 +    if var > 0 {
 +        panic!("p3 {var}", var = var);
 +    }
 +
 +    #[allow(non_fmt_panics)]
 +    {
 +        if var > 0 {
 +            panic!("p4 {var}");
 +        }
 +    }
++
++    assert!(var == 1, "p5 {}", var);
++    debug_assert!(var == 1, "p6 {}", var);
 +}
index faf8ca4d3a797aa2e989571786cd8c317a2e6652,0000000000000000000000000000000000000000..ee72065e28abf3bfb0c118de65166efd65a7f6a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,32 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::uninlined_format_args)]
 +
 +fn main() {
 +    let var = 1;
 +
 +    println!("val='{var}'");
 +
 +    if var > 0 {
 +        panic!("p1 {var}");
 +    }
 +    if var > 0 {
 +        panic!("p2 {var}");
 +    }
 +    if var > 0 {
 +        panic!("p3 {var}");
 +    }
 +
 +    #[allow(non_fmt_panics)]
 +    {
 +        if var > 0 {
 +            panic!("p4 {var}");
 +        }
 +    }
++
++    assert!(var == 1, "p5 {var}");
++    debug_assert!(var == 1, "p6 {var}");
 +}
index 0f09c45f41324b94da38117a4d885deabe904c0f,0000000000000000000000000000000000000000..fc7b125080e766296e83e69e253dd481640b4e11
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,75 @@@
- error: aborting due to 4 previous errors
 +error: variables can be used directly in the `format!` string
 +  --> $DIR/uninlined_format_args_panic.rs:11:5
 +   |
 +LL |     println!("val='{}'", var);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
 +help: change this to
 +   |
 +LL -     println!("val='{}'", var);
 +LL +     println!("val='{var}'");
 +   |
 +
 +error: variables can be used directly in the `format!` string
 +  --> $DIR/uninlined_format_args_panic.rs:14:9
 +   |
 +LL |         panic!("p1 {}", var);
 +   |         ^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL -         panic!("p1 {}", var);
 +LL +         panic!("p1 {var}");
 +   |
 +
 +error: variables can be used directly in the `format!` string
 +  --> $DIR/uninlined_format_args_panic.rs:17:9
 +   |
 +LL |         panic!("p2 {0}", var);
 +   |         ^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL -         panic!("p2 {0}", var);
 +LL +         panic!("p2 {var}");
 +   |
 +
 +error: variables can be used directly in the `format!` string
 +  --> $DIR/uninlined_format_args_panic.rs:20:9
 +   |
 +LL |         panic!("p3 {var}", var = var);
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL -         panic!("p3 {var}", var = var);
 +LL +         panic!("p3 {var}");
 +   |
 +
++error: variables can be used directly in the `format!` string
++  --> $DIR/uninlined_format_args_panic.rs:30:5
++   |
++LL |     assert!(var == 1, "p5 {}", var);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++help: change this to
++   |
++LL -     assert!(var == 1, "p5 {}", var);
++LL +     assert!(var == 1, "p5 {var}");
++   |
++
++error: variables can be used directly in the `format!` string
++  --> $DIR/uninlined_format_args_panic.rs:31:5
++   |
++LL |     debug_assert!(var == 1, "p6 {}", var);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++help: change this to
++   |
++LL -     debug_assert!(var == 1, "p6 {}", var);
++LL +     debug_assert!(var == 1, "p6 {var}");
++   |
++
++error: aborting due to 6 previous errors
 +
index 6421c5bbed2f5a05a6b5523d8560f36a374ca6c3,0000000000000000000000000000000000000000..b4a0a0f496e400d7bdb3c4d8f9444c12cb6549f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,32 @@@
 +// revisions: edition2018 edition2021
 +//[edition2018] edition:2018
 +//[edition2021] edition:2021
 +// run-rustfix
 +
 +#![warn(clippy::uninlined_format_args)]
 +
 +fn main() {
 +    let var = 1;
 +
 +    println!("val='{}'", var);
 +
 +    if var > 0 {
 +        panic!("p1 {}", var);
 +    }
 +    if var > 0 {
 +        panic!("p2 {0}", var);
 +    }
 +    if var > 0 {
 +        panic!("p3 {var}", var = var);
 +    }
 +
 +    #[allow(non_fmt_panics)]
 +    {
 +        if var > 0 {
 +            panic!("p4 {var}");
 +        }
 +    }
++
++    assert!(var == 1, "p5 {}", var);
++    debug_assert!(var == 1, "p6 {}", var);
 +}
index ddeda795f81793e8d70d7109a16c958a4821f7f0,0000000000000000000000000000000000000000..345f6d604c4f005028cfda81242cbc275ba6923b
mode 100644,000000..100644
--- /dev/null
@@@ -1,456 -1,0 +1,476 @@@
 +// run-rustfix
 +
 +#![allow(clippy::needless_borrow, clippy::ptr_arg)]
 +#![warn(clippy::unnecessary_to_owned)]
 +
 +use std::borrow::Cow;
 +use std::ffi::{CStr, CString, OsStr, OsString};
 +use std::ops::Deref;
 +
 +#[derive(Clone)]
 +struct X(String);
 +
 +impl Deref for X {
 +    type Target = [u8];
 +    fn deref(&self) -> &[u8] {
 +        self.0.as_bytes()
 +    }
 +}
 +
 +impl AsRef<str> for X {
 +    fn as_ref(&self) -> &str {
 +        self.0.as_str()
 +    }
 +}
 +
 +impl ToString for X {
 +    fn to_string(&self) -> String {
 +        self.0.to_string()
 +    }
 +}
 +
 +impl X {
 +    fn join(&self, other: impl AsRef<str>) -> Self {
 +        let mut s = self.0.clone();
 +        s.push_str(other.as_ref());
 +        Self(s)
 +    }
 +}
 +
 +#[allow(dead_code)]
 +#[derive(Clone)]
 +enum FileType {
 +    Account,
 +    PrivateKey,
 +    Certificate,
 +}
 +
 +fn main() {
 +    let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
 +    let os_str = OsStr::new("x");
 +    let path = std::path::Path::new("x");
 +    let s = "x";
 +    let array = ["x"];
 +    let array_ref = &["x"];
 +    let slice = &["x"][..];
 +    let x = X(String::from("x"));
 +    let x_ref = &x;
 +
 +    require_c_str(&Cow::from(c_str));
 +    require_c_str(c_str);
 +
 +    require_os_str(os_str);
 +    require_os_str(&Cow::from(os_str));
 +    require_os_str(os_str);
 +
 +    require_path(path);
 +    require_path(&Cow::from(path));
 +    require_path(path);
 +
 +    require_str(s);
 +    require_str(&Cow::from(s));
 +    require_str(s);
 +    require_str(x_ref.as_ref());
 +
 +    require_slice(slice);
 +    require_slice(&Cow::from(slice));
 +    require_slice(array.as_ref());
 +    require_slice(array_ref.as_ref());
 +    require_slice(slice);
 +    require_slice(&x_ref.to_owned()); // No longer flagged because of #8759.
 +
 +    require_x(&Cow::<X>::Owned(x.clone()));
 +    require_x(&x_ref.to_owned()); // No longer flagged because of #8759.
 +
 +    require_deref_c_str(c_str);
 +    require_deref_os_str(os_str);
 +    require_deref_path(path);
 +    require_deref_str(s);
 +    require_deref_slice(slice);
 +
 +    require_impl_deref_c_str(c_str);
 +    require_impl_deref_os_str(os_str);
 +    require_impl_deref_path(path);
 +    require_impl_deref_str(s);
 +    require_impl_deref_slice(slice);
 +
 +    require_deref_str_slice(s, slice);
 +    require_deref_slice_str(slice, s);
 +
 +    require_as_ref_c_str(c_str);
 +    require_as_ref_os_str(os_str);
 +    require_as_ref_path(path);
 +    require_as_ref_str(s);
 +    require_as_ref_str(&x);
 +    require_as_ref_slice(array);
 +    require_as_ref_slice(array_ref);
 +    require_as_ref_slice(slice);
 +
 +    require_impl_as_ref_c_str(c_str);
 +    require_impl_as_ref_os_str(os_str);
 +    require_impl_as_ref_path(path);
 +    require_impl_as_ref_str(s);
 +    require_impl_as_ref_str(&x);
 +    require_impl_as_ref_slice(array);
 +    require_impl_as_ref_slice(array_ref);
 +    require_impl_as_ref_slice(slice);
 +
 +    require_as_ref_str_slice(s, array);
 +    require_as_ref_str_slice(s, array_ref);
 +    require_as_ref_str_slice(s, slice);
 +    require_as_ref_slice_str(array, s);
 +    require_as_ref_slice_str(array_ref, s);
 +    require_as_ref_slice_str(slice, s);
 +
 +    let _ = x.join(x_ref);
 +
 +    let _ = slice.iter().copied();
 +    let _ = slice.iter().copied();
 +    let _ = [std::path::PathBuf::new()][..].iter().cloned();
 +    let _ = [std::path::PathBuf::new()][..].iter().cloned();
 +
 +    let _ = slice.iter().copied();
 +    let _ = slice.iter().copied();
 +    let _ = [std::path::PathBuf::new()][..].iter().cloned();
 +    let _ = [std::path::PathBuf::new()][..].iter().cloned();
 +
 +    let _ = check_files(&[FileType::Account]);
 +
 +    // negative tests
 +    require_string(&s.to_string());
 +    require_string(&Cow::from(s).into_owned());
 +    require_string(&s.to_owned());
 +    require_string(&x_ref.to_string());
 +
 +    // `X` isn't copy.
 +    require_slice(&x.to_owned());
 +    require_deref_slice(x.to_owned());
 +
 +    // The following should be flagged by `redundant_clone`, but not by this lint.
 +    require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap());
 +    require_os_str(&OsString::from("x"));
 +    require_path(&std::path::PathBuf::from("x"));
 +    require_str(&String::from("x"));
 +    require_slice(&[String::from("x")]);
 +}
 +
 +fn require_c_str(_: &CStr) {}
 +fn require_os_str(_: &OsStr) {}
 +fn require_path(_: &std::path::Path) {}
 +fn require_str(_: &str) {}
 +fn require_slice<T>(_: &[T]) {}
 +fn require_x(_: &X) {}
 +
 +fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
 +fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
 +fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
 +fn require_deref_str<T: Deref<Target = str>>(_: T) {}
 +fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
 +
 +fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
 +fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
 +fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
 +fn require_impl_deref_str(_: impl Deref<Target = str>) {}
 +fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
 +
 +fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
 +fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
 +
 +fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
 +fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
 +fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
 +fn require_as_ref_str<T: AsRef<str>>(_: T) {}
 +fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
 +
 +fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
 +fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
 +fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
 +fn require_impl_as_ref_str(_: impl AsRef<str>) {}
 +fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
 +
 +fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
 +fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
 +
 +// `check_files` is based on:
 +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
 +fn check_files(file_types: &[FileType]) -> bool {
 +    for t in file_types {
 +        let path = match get_file_path(t) {
 +            Ok(p) => p,
 +            Err(_) => {
 +                return false;
 +            },
 +        };
 +        if !path.is_file() {
 +            return false;
 +        }
 +    }
 +    true
 +}
 +
 +fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
 +    Ok(std::path::PathBuf::new())
 +}
 +
 +fn require_string(_: &String) {}
 +
 +#[clippy::msrv = "1.35"]
 +fn _msrv_1_35() {
 +    // `copied` was stabilized in 1.36, so clippy should use `cloned`.
 +    let _ = &["x"][..].iter().cloned();
 +}
 +
 +#[clippy::msrv = "1.36"]
 +fn _msrv_1_36() {
 +    let _ = &["x"][..].iter().copied();
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/8507
 +mod issue_8507 {
 +    #![allow(dead_code)]
 +
 +    struct Opaque<P>(P);
 +
 +    pub trait Abstracted {}
 +
 +    impl<P> Abstracted for Opaque<P> {}
 +
 +    fn build<P>(p: P) -> Opaque<P>
 +    where
 +        P: AsRef<str>,
 +    {
 +        Opaque(p)
 +    }
 +
 +    // Should not lint.
 +    fn test_str(s: &str) -> Box<dyn Abstracted> {
 +        Box::new(build(s.to_string()))
 +    }
 +
 +    // Should not lint.
 +    fn test_x(x: super::X) -> Box<dyn Abstracted> {
 +        Box::new(build(x))
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    struct Y(&'static str);
 +
 +    impl AsRef<str> for Y {
 +        fn as_ref(&self) -> &str {
 +            self.0
 +        }
 +    }
 +
 +    impl ToString for Y {
 +        fn to_string(&self) -> String {
 +            self.0.to_string()
 +        }
 +    }
 +
 +    // Should lint because Y is copy.
 +    fn test_y(y: Y) -> Box<dyn Abstracted> {
 +        Box::new(build(y))
 +    }
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/8759
 +mod issue_8759 {
 +    #![allow(dead_code)]
 +
 +    #[derive(Default)]
 +    struct View {}
 +
 +    impl std::borrow::ToOwned for View {
 +        type Owned = View;
 +        fn to_owned(&self) -> Self::Owned {
 +            View {}
 +        }
 +    }
 +
 +    #[derive(Default)]
 +    struct RenderWindow {
 +        default_view: View,
 +    }
 +
 +    impl RenderWindow {
 +        fn default_view(&self) -> &View {
 +            &self.default_view
 +        }
 +        fn set_view(&mut self, _view: &View) {}
 +    }
 +
 +    fn main() {
 +        let mut rw = RenderWindow::default();
 +        rw.set_view(&rw.default_view().to_owned());
 +    }
 +}
 +
 +mod issue_8759_variant {
 +    #![allow(dead_code)]
 +
 +    #[derive(Clone, Default)]
 +    struct View {}
 +
 +    #[derive(Default)]
 +    struct RenderWindow {
 +        default_view: View,
 +    }
 +
 +    impl RenderWindow {
 +        fn default_view(&self) -> &View {
 +            &self.default_view
 +        }
 +        fn set_view(&mut self, _view: &View) {}
 +    }
 +
 +    fn main() {
 +        let mut rw = RenderWindow::default();
 +        rw.set_view(&rw.default_view().to_owned());
 +    }
 +}
 +
 +mod issue_9317 {
 +    #![allow(dead_code)]
 +
 +    struct Bytes {}
 +
 +    impl ToString for Bytes {
 +        fn to_string(&self) -> String {
 +            "123".to_string()
 +        }
 +    }
 +
 +    impl AsRef<[u8]> for Bytes {
 +        fn as_ref(&self) -> &[u8] {
 +            &[1, 2, 3]
 +        }
 +    }
 +
 +    fn consume<C: AsRef<[u8]>>(c: C) {
 +        let _ = c;
 +    }
 +
 +    pub fn main() {
 +        let b = Bytes {};
 +        // Should not lint.
 +        consume(b.to_string());
 +    }
 +}
 +
 +mod issue_9351 {
 +    #![allow(dead_code)]
 +
 +    use std::ops::Deref;
 +    use std::path::{Path, PathBuf};
 +
 +    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
 +        x
 +    }
 +
 +    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
 +
 +    fn id<T: AsRef<str>>(x: T) -> T {
 +        x
 +    }
 +
 +    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
 +
 +    // Should lint
 +    fn single_return() -> impl AsRef<str> {
 +        id("abc")
 +    }
 +
 +    // Should not lint
 +    fn multiple_returns(b: bool) -> impl AsRef<str> {
 +        if b {
 +            return String::new();
 +        }
 +
 +        id("abc".to_string())
 +    }
 +
 +    struct S1(String);
 +
 +    // Should not lint
 +    fn fields1() -> S1 {
 +        S1(id("abc".to_string()))
 +    }
 +
 +    struct S2 {
 +        s: String,
 +    }
 +
 +    // Should not lint
 +    fn fields2() {
 +        let mut s = S2 { s: "abc".into() };
 +        s.s = id("abc".to_string());
 +    }
 +
 +    pub fn main() {
 +        let path = std::path::Path::new("x");
 +        let path_buf = path.to_owned();
 +
 +        // Should not lint.
 +        let _x: PathBuf = require_deref_path(path.to_owned());
 +        generic_arg_used_elsewhere(path.to_owned(), path_buf);
 +        predicates_are_satisfied(id("abc".to_string()));
 +    }
 +}
 +
 +mod issue_9504 {
 +    #![allow(dead_code)]
 +
 +    async fn foo<S: AsRef<str>>(_: S) {}
 +    async fn bar() {
 +        foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
 +    }
 +}
 +
 +mod issue_9771a {
 +    #![allow(dead_code)]
 +
 +    use std::marker::PhantomData;
 +
 +    pub struct Key<K: AsRef<[u8]>, V: ?Sized>(K, PhantomData<V>);
 +
 +    impl<K: AsRef<[u8]>, V: ?Sized> Key<K, V> {
 +        pub fn new(key: K) -> Key<K, V> {
 +            Key(key, PhantomData)
 +        }
 +    }
 +
 +    pub fn pkh(pkh: &[u8]) -> Key<Vec<u8>, String> {
 +        Key::new([b"pkh-", pkh].concat().to_vec())
 +    }
 +}
 +
 +mod issue_9771b {
 +    #![allow(dead_code)]
 +
 +    pub struct Key<K: AsRef<[u8]>>(K);
 +
 +    pub fn from(c: &[u8]) -> Key<Vec<u8>> {
 +        let v = [c].concat();
 +        Key(v.to_vec())
 +    }
 +}
++
++// This is a watered down version of the code in: https://github.com/oxigraph/rio
++// The ICE is triggered by the call to `to_owned` on this line:
++// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
++mod issue_10021 {
++    #![allow(unused)]
++
++    pub struct Iri<T>(T);
++
++    impl<T: AsRef<str>> Iri<T> {
++        pub fn parse(iri: T) -> Result<Self, ()> {
++            unimplemented!()
++        }
++    }
++
++    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
++        let base_iri = Iri::parse(url.to_owned())?;
++        Ok(())
++    }
++}
index 95d2576733cd75ea8e42bf0ea127fb8983f7e451,0000000000000000000000000000000000000000..7eb53df39e5b7dace2e82dd95030c53282b01919
mode 100644,000000..100644
--- /dev/null
@@@ -1,456 -1,0 +1,476 @@@
 +// run-rustfix
 +
 +#![allow(clippy::needless_borrow, clippy::ptr_arg)]
 +#![warn(clippy::unnecessary_to_owned)]
 +
 +use std::borrow::Cow;
 +use std::ffi::{CStr, CString, OsStr, OsString};
 +use std::ops::Deref;
 +
 +#[derive(Clone)]
 +struct X(String);
 +
 +impl Deref for X {
 +    type Target = [u8];
 +    fn deref(&self) -> &[u8] {
 +        self.0.as_bytes()
 +    }
 +}
 +
 +impl AsRef<str> for X {
 +    fn as_ref(&self) -> &str {
 +        self.0.as_str()
 +    }
 +}
 +
 +impl ToString for X {
 +    fn to_string(&self) -> String {
 +        self.0.to_string()
 +    }
 +}
 +
 +impl X {
 +    fn join(&self, other: impl AsRef<str>) -> Self {
 +        let mut s = self.0.clone();
 +        s.push_str(other.as_ref());
 +        Self(s)
 +    }
 +}
 +
 +#[allow(dead_code)]
 +#[derive(Clone)]
 +enum FileType {
 +    Account,
 +    PrivateKey,
 +    Certificate,
 +}
 +
 +fn main() {
 +    let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
 +    let os_str = OsStr::new("x");
 +    let path = std::path::Path::new("x");
 +    let s = "x";
 +    let array = ["x"];
 +    let array_ref = &["x"];
 +    let slice = &["x"][..];
 +    let x = X(String::from("x"));
 +    let x_ref = &x;
 +
 +    require_c_str(&Cow::from(c_str).into_owned());
 +    require_c_str(&c_str.to_owned());
 +
 +    require_os_str(&os_str.to_os_string());
 +    require_os_str(&Cow::from(os_str).into_owned());
 +    require_os_str(&os_str.to_owned());
 +
 +    require_path(&path.to_path_buf());
 +    require_path(&Cow::from(path).into_owned());
 +    require_path(&path.to_owned());
 +
 +    require_str(&s.to_string());
 +    require_str(&Cow::from(s).into_owned());
 +    require_str(&s.to_owned());
 +    require_str(&x_ref.to_string());
 +
 +    require_slice(&slice.to_vec());
 +    require_slice(&Cow::from(slice).into_owned());
 +    require_slice(&array.to_owned());
 +    require_slice(&array_ref.to_owned());
 +    require_slice(&slice.to_owned());
 +    require_slice(&x_ref.to_owned()); // No longer flagged because of #8759.
 +
 +    require_x(&Cow::<X>::Owned(x.clone()).into_owned());
 +    require_x(&x_ref.to_owned()); // No longer flagged because of #8759.
 +
 +    require_deref_c_str(c_str.to_owned());
 +    require_deref_os_str(os_str.to_owned());
 +    require_deref_path(path.to_owned());
 +    require_deref_str(s.to_owned());
 +    require_deref_slice(slice.to_owned());
 +
 +    require_impl_deref_c_str(c_str.to_owned());
 +    require_impl_deref_os_str(os_str.to_owned());
 +    require_impl_deref_path(path.to_owned());
 +    require_impl_deref_str(s.to_owned());
 +    require_impl_deref_slice(slice.to_owned());
 +
 +    require_deref_str_slice(s.to_owned(), slice.to_owned());
 +    require_deref_slice_str(slice.to_owned(), s.to_owned());
 +
 +    require_as_ref_c_str(c_str.to_owned());
 +    require_as_ref_os_str(os_str.to_owned());
 +    require_as_ref_path(path.to_owned());
 +    require_as_ref_str(s.to_owned());
 +    require_as_ref_str(x.to_owned());
 +    require_as_ref_slice(array.to_owned());
 +    require_as_ref_slice(array_ref.to_owned());
 +    require_as_ref_slice(slice.to_owned());
 +
 +    require_impl_as_ref_c_str(c_str.to_owned());
 +    require_impl_as_ref_os_str(os_str.to_owned());
 +    require_impl_as_ref_path(path.to_owned());
 +    require_impl_as_ref_str(s.to_owned());
 +    require_impl_as_ref_str(x.to_owned());
 +    require_impl_as_ref_slice(array.to_owned());
 +    require_impl_as_ref_slice(array_ref.to_owned());
 +    require_impl_as_ref_slice(slice.to_owned());
 +
 +    require_as_ref_str_slice(s.to_owned(), array.to_owned());
 +    require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
 +    require_as_ref_str_slice(s.to_owned(), slice.to_owned());
 +    require_as_ref_slice_str(array.to_owned(), s.to_owned());
 +    require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
 +    require_as_ref_slice_str(slice.to_owned(), s.to_owned());
 +
 +    let _ = x.join(&x_ref.to_string());
 +
 +    let _ = slice.to_vec().into_iter();
 +    let _ = slice.to_owned().into_iter();
 +    let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
 +    let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
 +
 +    let _ = IntoIterator::into_iter(slice.to_vec());
 +    let _ = IntoIterator::into_iter(slice.to_owned());
 +    let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
 +    let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
 +
 +    let _ = check_files(&[FileType::Account]);
 +
 +    // negative tests
 +    require_string(&s.to_string());
 +    require_string(&Cow::from(s).into_owned());
 +    require_string(&s.to_owned());
 +    require_string(&x_ref.to_string());
 +
 +    // `X` isn't copy.
 +    require_slice(&x.to_owned());
 +    require_deref_slice(x.to_owned());
 +
 +    // The following should be flagged by `redundant_clone`, but not by this lint.
 +    require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
 +    require_os_str(&OsString::from("x").to_os_string());
 +    require_path(&std::path::PathBuf::from("x").to_path_buf());
 +    require_str(&String::from("x").to_string());
 +    require_slice(&[String::from("x")].to_owned());
 +}
 +
 +fn require_c_str(_: &CStr) {}
 +fn require_os_str(_: &OsStr) {}
 +fn require_path(_: &std::path::Path) {}
 +fn require_str(_: &str) {}
 +fn require_slice<T>(_: &[T]) {}
 +fn require_x(_: &X) {}
 +
 +fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
 +fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
 +fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
 +fn require_deref_str<T: Deref<Target = str>>(_: T) {}
 +fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
 +
 +fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
 +fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
 +fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
 +fn require_impl_deref_str(_: impl Deref<Target = str>) {}
 +fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
 +
 +fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
 +fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
 +
 +fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
 +fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
 +fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
 +fn require_as_ref_str<T: AsRef<str>>(_: T) {}
 +fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
 +
 +fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
 +fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
 +fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
 +fn require_impl_as_ref_str(_: impl AsRef<str>) {}
 +fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
 +
 +fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
 +fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
 +
 +// `check_files` is based on:
 +// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
 +fn check_files(file_types: &[FileType]) -> bool {
 +    for t in file_types.to_vec() {
 +        let path = match get_file_path(&t) {
 +            Ok(p) => p,
 +            Err(_) => {
 +                return false;
 +            },
 +        };
 +        if !path.is_file() {
 +            return false;
 +        }
 +    }
 +    true
 +}
 +
 +fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
 +    Ok(std::path::PathBuf::new())
 +}
 +
 +fn require_string(_: &String) {}
 +
 +#[clippy::msrv = "1.35"]
 +fn _msrv_1_35() {
 +    // `copied` was stabilized in 1.36, so clippy should use `cloned`.
 +    let _ = &["x"][..].to_vec().into_iter();
 +}
 +
 +#[clippy::msrv = "1.36"]
 +fn _msrv_1_36() {
 +    let _ = &["x"][..].to_vec().into_iter();
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/8507
 +mod issue_8507 {
 +    #![allow(dead_code)]
 +
 +    struct Opaque<P>(P);
 +
 +    pub trait Abstracted {}
 +
 +    impl<P> Abstracted for Opaque<P> {}
 +
 +    fn build<P>(p: P) -> Opaque<P>
 +    where
 +        P: AsRef<str>,
 +    {
 +        Opaque(p)
 +    }
 +
 +    // Should not lint.
 +    fn test_str(s: &str) -> Box<dyn Abstracted> {
 +        Box::new(build(s.to_string()))
 +    }
 +
 +    // Should not lint.
 +    fn test_x(x: super::X) -> Box<dyn Abstracted> {
 +        Box::new(build(x))
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    struct Y(&'static str);
 +
 +    impl AsRef<str> for Y {
 +        fn as_ref(&self) -> &str {
 +            self.0
 +        }
 +    }
 +
 +    impl ToString for Y {
 +        fn to_string(&self) -> String {
 +            self.0.to_string()
 +        }
 +    }
 +
 +    // Should lint because Y is copy.
 +    fn test_y(y: Y) -> Box<dyn Abstracted> {
 +        Box::new(build(y.to_string()))
 +    }
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/8759
 +mod issue_8759 {
 +    #![allow(dead_code)]
 +
 +    #[derive(Default)]
 +    struct View {}
 +
 +    impl std::borrow::ToOwned for View {
 +        type Owned = View;
 +        fn to_owned(&self) -> Self::Owned {
 +            View {}
 +        }
 +    }
 +
 +    #[derive(Default)]
 +    struct RenderWindow {
 +        default_view: View,
 +    }
 +
 +    impl RenderWindow {
 +        fn default_view(&self) -> &View {
 +            &self.default_view
 +        }
 +        fn set_view(&mut self, _view: &View) {}
 +    }
 +
 +    fn main() {
 +        let mut rw = RenderWindow::default();
 +        rw.set_view(&rw.default_view().to_owned());
 +    }
 +}
 +
 +mod issue_8759_variant {
 +    #![allow(dead_code)]
 +
 +    #[derive(Clone, Default)]
 +    struct View {}
 +
 +    #[derive(Default)]
 +    struct RenderWindow {
 +        default_view: View,
 +    }
 +
 +    impl RenderWindow {
 +        fn default_view(&self) -> &View {
 +            &self.default_view
 +        }
 +        fn set_view(&mut self, _view: &View) {}
 +    }
 +
 +    fn main() {
 +        let mut rw = RenderWindow::default();
 +        rw.set_view(&rw.default_view().to_owned());
 +    }
 +}
 +
 +mod issue_9317 {
 +    #![allow(dead_code)]
 +
 +    struct Bytes {}
 +
 +    impl ToString for Bytes {
 +        fn to_string(&self) -> String {
 +            "123".to_string()
 +        }
 +    }
 +
 +    impl AsRef<[u8]> for Bytes {
 +        fn as_ref(&self) -> &[u8] {
 +            &[1, 2, 3]
 +        }
 +    }
 +
 +    fn consume<C: AsRef<[u8]>>(c: C) {
 +        let _ = c;
 +    }
 +
 +    pub fn main() {
 +        let b = Bytes {};
 +        // Should not lint.
 +        consume(b.to_string());
 +    }
 +}
 +
 +mod issue_9351 {
 +    #![allow(dead_code)]
 +
 +    use std::ops::Deref;
 +    use std::path::{Path, PathBuf};
 +
 +    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
 +        x
 +    }
 +
 +    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
 +
 +    fn id<T: AsRef<str>>(x: T) -> T {
 +        x
 +    }
 +
 +    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
 +
 +    // Should lint
 +    fn single_return() -> impl AsRef<str> {
 +        id("abc".to_string())
 +    }
 +
 +    // Should not lint
 +    fn multiple_returns(b: bool) -> impl AsRef<str> {
 +        if b {
 +            return String::new();
 +        }
 +
 +        id("abc".to_string())
 +    }
 +
 +    struct S1(String);
 +
 +    // Should not lint
 +    fn fields1() -> S1 {
 +        S1(id("abc".to_string()))
 +    }
 +
 +    struct S2 {
 +        s: String,
 +    }
 +
 +    // Should not lint
 +    fn fields2() {
 +        let mut s = S2 { s: "abc".into() };
 +        s.s = id("abc".to_string());
 +    }
 +
 +    pub fn main() {
 +        let path = std::path::Path::new("x");
 +        let path_buf = path.to_owned();
 +
 +        // Should not lint.
 +        let _x: PathBuf = require_deref_path(path.to_owned());
 +        generic_arg_used_elsewhere(path.to_owned(), path_buf);
 +        predicates_are_satisfied(id("abc".to_string()));
 +    }
 +}
 +
 +mod issue_9504 {
 +    #![allow(dead_code)]
 +
 +    async fn foo<S: AsRef<str>>(_: S) {}
 +    async fn bar() {
 +        foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
 +    }
 +}
 +
 +mod issue_9771a {
 +    #![allow(dead_code)]
 +
 +    use std::marker::PhantomData;
 +
 +    pub struct Key<K: AsRef<[u8]>, V: ?Sized>(K, PhantomData<V>);
 +
 +    impl<K: AsRef<[u8]>, V: ?Sized> Key<K, V> {
 +        pub fn new(key: K) -> Key<K, V> {
 +            Key(key, PhantomData)
 +        }
 +    }
 +
 +    pub fn pkh(pkh: &[u8]) -> Key<Vec<u8>, String> {
 +        Key::new([b"pkh-", pkh].concat().to_vec())
 +    }
 +}
 +
 +mod issue_9771b {
 +    #![allow(dead_code)]
 +
 +    pub struct Key<K: AsRef<[u8]>>(K);
 +
 +    pub fn from(c: &[u8]) -> Key<Vec<u8>> {
 +        let v = [c].concat();
 +        Key(v.to_vec())
 +    }
 +}
++
++// This is a watered down version of the code in: https://github.com/oxigraph/rio
++// The ICE is triggered by the call to `to_owned` on this line:
++// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
++mod issue_10021 {
++    #![allow(unused)]
++
++    pub struct Iri<T>(T);
++
++    impl<T: AsRef<str>> Iri<T> {
++        pub fn parse(iri: T) -> Result<Self, ()> {
++            unimplemented!()
++        }
++    }
++
++    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
++        let base_iri = Iri::parse(url.to_owned())?;
++        Ok(())
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8906c776977a80f30667b1f2cd24a1f881c6e904
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++// run-rustfix
++
++#![feature(lang_items, start, libc)]
++#![no_std]
++#![deny(clippy::zero_ptr)]
++
++#[start]
++fn main(_argc: isize, _argv: *const *const u8) -> isize {
++    let _ = core::ptr::null::<usize>();
++    let _ = core::ptr::null_mut::<f64>();
++    let _: *const u8 = core::ptr::null();
++    0
++}
++
++#[panic_handler]
++fn panic(_info: &core::panic::PanicInfo) -> ! {
++    loop {}
++}
++
++#[lang = "eh_personality"]
++extern "C" fn eh_personality() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..379c1b18d299200f914656a4acee9ff6107edd04
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++// run-rustfix
++
++#![feature(lang_items, start, libc)]
++#![no_std]
++#![deny(clippy::zero_ptr)]
++
++#[start]
++fn main(_argc: isize, _argv: *const *const u8) -> isize {
++    let _ = 0 as *const usize;
++    let _ = 0 as *mut f64;
++    let _: *const u8 = 0 as *const _;
++    0
++}
++
++#[panic_handler]
++fn panic(_info: &core::panic::PanicInfo) -> ! {
++    loop {}
++}
++
++#[lang = "eh_personality"]
++extern "C" fn eh_personality() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d92bb4a6528dbb7afca9c2441db814366da63890
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++error: `0 as *const _` detected
++  --> $DIR/zero_ptr_no_std.rs:9:13
++   |
++LL |     let _ = 0 as *const usize;
++   |             ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()`
++   |
++note: the lint level is defined here
++  --> $DIR/zero_ptr_no_std.rs:5:9
++   |
++LL | #![deny(clippy::zero_ptr)]
++   |         ^^^^^^^^^^^^^^^^
++
++error: `0 as *mut _` detected
++  --> $DIR/zero_ptr_no_std.rs:10:13
++   |
++LL |     let _ = 0 as *mut f64;
++   |             ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()`
++
++error: `0 as *const _` detected
++  --> $DIR/zero_ptr_no_std.rs:11:24
++   |
++LL |     let _: *const u8 = 0 as *const _;
++   |                        ^^^^^^^^^^^^^ help: try: `core::ptr::null()`
++
++error: aborting due to 3 previous errors
++
index 7a85386a3df4b8fc9934fe30010e5f87820fe12d,0000000000000000000000000000000000000000..c721e9969c9aa67497c32ab03d2510e6e6ecaf11
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,93 @@@
- use rustc_tools_util::VersionInfo;
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +#![allow(clippy::single_match_else)]
 +
 +use std::fs;
 +
 +#[test]
 +fn consistent_clippy_crate_versions() {
 +    fn read_version(path: &str) -> String {
 +        let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{path}`: {e:?}"));
 +        contents
 +            .lines()
 +            .filter_map(|l| l.split_once('='))
 +            .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))
 +            .unwrap_or_else(|| panic!("error finding version in `{path}`"))
 +            .to_string()
 +    }
 +
 +    // do not run this test inside the upstream rustc repo:
 +    // https://github.com/rust-lang/rust-clippy/issues/6683
 +    if option_env!("RUSTC_TEST_SUITE").is_some() {
 +        return;
 +    }
 +
 +    let clippy_version = read_version("Cargo.toml");
 +
 +    let paths = [
 +        "declare_clippy_lint/Cargo.toml",
 +        "clippy_lints/Cargo.toml",
 +        "clippy_utils/Cargo.toml",
 +    ];
 +
 +    for path in paths {
 +        assert_eq!(clippy_version, read_version(path), "{path} version differs");
 +    }
 +}
 +
 +#[test]
 +fn check_that_clippy_has_the_same_major_version_as_rustc() {
 +    // do not run this test inside the upstream rustc repo:
 +    // https://github.com/rust-lang/rust-clippy/issues/6683
 +    if option_env!("RUSTC_TEST_SUITE").is_some() {
 +        return;
 +    }
 +
 +    let clippy_version = rustc_tools_util::get_version_info!();
 +    let clippy_major = clippy_version.major;
 +    let clippy_minor = clippy_version.minor;
 +    let clippy_patch = clippy_version.patch;
 +
 +    // get the rustc version either from the rustc installed with the toolchain file or from
 +    // `RUSTC_REAL` if Clippy is build in the Rust repo with `./x.py`.
 +    let rustc = std::env::var("RUSTC_REAL").unwrap_or_else(|_| "rustc".to_string());
 +    let rustc_version = String::from_utf8(
 +        std::process::Command::new(rustc)
 +            .arg("--version")
 +            .output()
 +            .expect("failed to run `rustc --version`")
 +            .stdout,
 +    )
 +    .unwrap();
 +    // extract "1 XX 0" from "rustc 1.XX.0-nightly (<commit> <date>)"
 +    let vsplit: Vec<&str> = rustc_version
 +        .split(' ')
 +        .nth(1)
 +        .unwrap()
 +        .split('-')
 +        .next()
 +        .unwrap()
 +        .split('.')
 +        .collect();
 +    match vsplit.as_slice() {
 +        [rustc_major, rustc_minor, _rustc_patch] => {
 +            // clippy 0.1.XX should correspond to rustc 1.XX.0
 +            assert_eq!(clippy_major, 0); // this will probably stay the same for a long time
 +            assert_eq!(
 +                clippy_minor.to_string(),
 +                *rustc_major,
 +                "clippy minor version does not equal rustc major version"
 +            );
 +            assert_eq!(
 +                clippy_patch.to_string(),
 +                *rustc_minor,
 +                "clippy patch version does not equal rustc minor version"
 +            );
 +            // do not check rustc_patch because when a stable-patch-release is made (like 1.50.2),
 +            // we don't want our tests failing suddenly
 +        },
 +        _ => {
 +            panic!("Failed to parse rustc version: {vsplit:?}");
 +        },
 +    };
 +}
index acb476ee69628efc987a0785bae0ddb36ea85b46,0000000000000000000000000000000000000000..6f50ef932e11260ffbc86b75820f2b4aea76f3fd
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,29 @@@
-     "good-first-issue"
 +[relabel]
 +allow-unauthenticated = [
 +    "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*",
++    "good-first-issue", "beta-nominated"
 +]
 +
 +# Allows shortcuts like `@rustbot ready`
 +#
 +# See https://github.com/rust-lang/triagebot/wiki/Shortcuts
 +[shortcut]
 +
 +[autolabel."S-waiting-on-review"]
 +new_pr = true
 +
 +[assign]
 +contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
 +
 +[assign.owners]
 +"/.github" = ["@flip1995"]
 +"*" = [
 +    "@flip1995",
 +    "@Manishearth",
 +    "@llogiq",
 +    "@giraffate",
 +    "@xFrednet",
 +    "@Alexendoo",
 +    "@dswij",
 +    "@Jarcho",
 +]