]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '0eff589afc83e21a03a168497bbab6b4dfbb4ef6' into clippyup
authorflip1995 <philipp.krones@embecosm.com>
Thu, 30 Dec 2021 14:10:43 +0000 (15:10 +0100)
committerflip1995 <philipp.krones@embecosm.com>
Thu, 30 Dec 2021 14:10:43 +0000 (15:10 +0100)
80 files changed:
1  2 
src/tools/clippy/.github/workflows/clippy.yml
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/README.md
src/tools/clippy/clippy_lints/src/approx_const.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/float_literal.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
src/tools/clippy/clippy_lints/src/methods/utils.rs
src/tools/clippy/clippy_lints/src/needless_bool.rs
src/tools/clippy/clippy_lints/src/neg_multiply.rs
src/tools/clippy/clippy_lints/src/non_expressive_names.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/str_utils.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/ui/crashes/ice-7868.stderr
src/tools/clippy/tests/ui/enum_variants.rs
src/tools/clippy/tests/ui/enum_variants.stderr
src/tools/clippy/tests/ui/floating_point_rad.fixed
src/tools/clippy/tests/ui/floating_point_rad.rs
src/tools/clippy/tests/ui/floating_point_rad.stderr
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/iter_skip_next.fixed
src/tools/clippy/tests/ui/iter_skip_next.rs
src/tools/clippy/tests/ui/iter_skip_next.stderr
src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs
src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr
src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr
src/tools/clippy/tests/ui/needless_bool/fixable.fixed
src/tools/clippy/tests/ui/needless_bool/fixable.rs
src/tools/clippy/tests/ui/needless_bool/fixable.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/neg_multiply.fixed
src/tools/clippy/tests/ui/neg_multiply.rs
src/tools/clippy/tests/ui/neg_multiply.stderr
src/tools/clippy/tests/ui/numbered_fields.fixed
src/tools/clippy/tests/ui/numbered_fields.rs
src/tools/clippy/tests/ui/numbered_fields.stderr
src/tools/clippy/tests/ui/return_self_not_must_use.rs
src/tools/clippy/tests/ui/shadow.rs
src/tools/clippy/tests/ui/shadow.stderr
src/tools/clippy/tests/ui/short_circuit_statement.fixed
src/tools/clippy/tests/ui/short_circuit_statement.stderr
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
src/tools/clippy/tests/ui/unwrap_or_else_default.rs
src/tools/clippy/tests/ui/unwrap_or_else_default.stderr

index 0339de77f3cecf4e3ebad3e91b302398a5da368f,0000000000000000000000000000000000000000..3d8c39408a924b5601d27262e8cb91811cfc8456
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,91 @@@
 +name: Clippy Test
 +
 +on:
 +  push:
 +    # Ignore bors branches, since they are covered by `clippy_bors.yml`
 +    branches-ignore:
 +      - auto
 +      - try
 +    # Don't run Clippy tests, when only textfiles were modified
 +    paths-ignore:
 +    - 'COPYRIGHT'
 +    - 'LICENSE-*'
 +    - '**.md'
 +    - '**.txt'
 +  pull_request:
 +    # Don't run Clippy tests, when only textfiles were modified
 +    paths-ignore:
 +    - 'COPYRIGHT'
 +    - 'LICENSE-*'
 +    - '**.md'
 +    - '**.txt'
 +
 +env:
 +  RUST_BACKTRACE: 1
 +  CARGO_TARGET_DIR: '${{ github.workspace }}/target'
 +  NO_FMT_TEST: 1
 +
 +jobs:
 +  base:
 +    # NOTE: If you modify this job, make sure you copy the changes to clippy_bors.yml
 +    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@v2.3.3
 +
 +    - name: Install toolchain
 +      run: rustup show active-toolchain
 +
 +    # Run
 +    - name: Set LD_LIBRARY_PATH (Linux)
 +      run: |
 +        SYSROOT=$(rustc --print sysroot)
 +        echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
 +
 +    - name: Build
 +      run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
 +
 +    - name: Test
 +      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
 +
 +    - name: Test clippy_lints
 +      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
 +      working-directory: clippy_lints
 +
++    - name: Test clippy_utils
++      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
++      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 cargo-clippy
 +      run: ../target/debug/cargo-clippy
 +      working-directory: clippy_workspace_tests
 +
 +    - name: Test cargo-clippy --fix
 +      run: ../target/debug/cargo-clippy clippy --fix
 +      working-directory: clippy_workspace_tests
 +
 +    - name: Test clippy-driver
 +      run: bash .github/driver.sh
 +      env:
 +        OS: ${{ runner.os }}
 +
 +    - name: Test cargo dev new lint
 +      run: |
 +        cargo dev new_lint --name new_early_pass --pass early
 +        cargo dev new_lint --name new_late_pass --pass late
 +        cargo check
 +        git reset --hard HEAD
index 1f4d666c7a92c1f6761c2288a280c71ad586f2c3,0000000000000000000000000000000000000000..8b644aa28176b6e4fc44de9dcf81b3c8cd09dc58
mode 100644,000000..100644
--- /dev/null
@@@ -1,268 -1,0 +1,272 @@@
 +name: Clippy Test (bors)
 +
 +on:
 +  push:
 +    branches:
 +      - auto
 +      - try
 +
 +env:
 +  RUST_BACKTRACE: 1
 +  CARGO_TARGET_DIR: '${{ github.workspace }}/target'
 +  NO_FMT_TEST: 1
 +
 +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@v2.3.3
 +      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: 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: Checkout
 +      uses: actions/checkout@v2.3.3
 +
 +    - 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-lints,metadata-collector-lint
 +
 +    - name: Test
 +      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
 +
 +    - name: Test clippy_lints
 +      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
 +      working-directory: clippy_lints
 +
++    - name: Test clippy_utils
++      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
++      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 cargo-clippy
 +      run: ../target/debug/cargo-clippy
 +      working-directory: clippy_workspace_tests
 +
 +    - name: Test cargo-clippy --fix
 +      run: ../target/debug/cargo-clippy clippy --fix
 +      working-directory: clippy_workspace_tests
 +
 +    - name: Test clippy-driver
 +      run: bash .github/driver.sh
 +      env:
 +        OS: ${{ runner.os }}
 +
 +    - name: Test cargo dev new lint
 +      run: |
 +        cargo dev new_lint --name new_early_pass --pass early
 +        cargo dev new_lint --name new_late_pass --pass late
 +        cargo check
 +        git reset --hard HEAD
 +
 +  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@v2.3.3
 +
 +    - 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@v2.3.3
 +
 +    - 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, 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, integration_build, integration]
 +
 +    steps:
 +      - name: Mark the job as a failure
 +        run: exit 1
index 7b5279cda6ea396f48cf49df821ee9b48ab31075,0000000000000000000000000000000000000000..27bac4718b6c3b0c6705c7fcfb0578fd77dd372e
mode 100644,000000..100644
--- /dev/null
@@@ -1,3272 -1,0 +1,3387 @@@
- [b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
 +# Changelog
 +
 +All notable changes to this project will be documented in this file.
 +See [Changelog Update](doc/changelog_update.md) if you want to update this
 +document.
 +
 +## Unreleased / In Rust Nightly
 +
- Current beta, release 2021-12-02
++[e181011...master](https://github.com/rust-lang/rust-clippy/compare/e181011...master)
++
++## Rust 1.58 (beta)
++
++Current beta, release 2022-01-13
++
++[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011)
++
++### 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
 +
- [7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
++Current stable, released 2021-12-02
 +
- Current stable, released 2021-10-21
++[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)
 +* [`blacklisted_name`]: Now allows blacklisted 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/doc/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)
 +* [`blacklisted_name`]: 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 `{unnnecessary,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/doc/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
 +[`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
 +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 +[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 +[`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_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
 +[`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
 +[`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
 +[`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_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_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`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
 +[`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
 +[`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
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`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
 +[`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_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
 +[`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
 +[`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
 +[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
 +[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 +[`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_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_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`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_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
 +[`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
 +[`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_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_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_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
 +[`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_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_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_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_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_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_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
 +[`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
 +[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 +[`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_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_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`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_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_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_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`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_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_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_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_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
 +[`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
 +[`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
 +[`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
 +[`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_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
 +[`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
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`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
 +[`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
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`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_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_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
 +[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 +[`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
 +[`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
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 +[`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
 +[`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_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
 +[`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_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 +[`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_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_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`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
 +[`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
 +[`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
 +[`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_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`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
 +[`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
 +[`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_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`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
 +[`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
 +[`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
 +[`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
 +[`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
 +[`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
 +[`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_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`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_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_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`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
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index 97ff31b4bc5a3181727c5d8230ea463a6c1c170a,0000000000000000000000000000000000000000..fc663de8f792dfb3e086fbe8ebcc7022b663e85c
mode 100644,000000..100644
--- /dev/null
@@@ -1,383 -1,0 +1,383 @@@
- Clippys `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
 +# Contributing to Clippy
 +
 +Hello fellow Rustacean! Great to see your interest in compiler internals and lints!
 +
 +**First**: if you're unsure or afraid of _anything_, just ask or submit the issue or pull request anyway. You won't be
 +yelled at for giving it your best effort. The worst that can happen is that you'll be politely asked to change
 +something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
 +
 +Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
 +explains how you can contribute and how to get started.  If you have any questions about contributing or need help with
 +anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip].
 +
 +All contributors are expected to follow the [Rust Code of Conduct].
 +
 +- [Contributing to Clippy](#contributing-to-clippy)
 +  - [Getting started](#getting-started)
 +    - [High level approach](#high-level-approach)
 +    - [Finding something to fix/improve](#finding-something-to-fiximprove)
 +  - [Writing code](#writing-code)
 +  - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work)
 +    - [IntelliJ Rust](#intellij-rust)
 +    - [Rust Analyzer](#rust-analyzer)
 +  - [How Clippy works](#how-clippy-works)
 +  - [Syncing changes between Clippy and `rust-lang/rust`](#syncing-changes-between-clippy-and-rust-langrust)
 +    - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos)
 +    - [Performing the sync from `rust-lang/rust` to Clippy](#performing-the-sync-from-rust-langrust-to-clippy)
 +    - [Performing the sync from Clippy to `rust-lang/rust`](#performing-the-sync-from-clippy-to-rust-langrust)
 +    - [Defining remotes](#defining-remotes)
 +  - [Issue and PR triage](#issue-and-pr-triage)
 +  - [Bors and Homu](#bors-and-homu)
 +  - [Contributions](#contributions)
 +
 +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
 +[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
 +
 +## Getting started
 +
 +**Note: If this is your first time contributing to Clippy, you should
 +first read the [Basics docs](doc/basics.md).**
 +
 +### High level approach
 +
 +1. Find something to fix/improve
 +2. Change code (likely some file in `clippy_lints/src/`)
 +3. Follow the instructions in the [Basics docs](doc/basics.md) to get set up
 +4. Run `cargo test` in the root directory and wiggle code until it passes
 +5. Open a PR (also can be done after 2. if you run into problems)
 +
 +### Finding something to fix/improve
 +
 +All issues on Clippy are mentored, if you want help simply ask @Manishearth, @flip1995, @phansch
 +or @llogiq directly by mentioning them in the issue or over on [Zulip]. This list may be out of date.
 +All currently active mentors can be found [here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3)
 +
 +Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy
 +issues. You can use `@rustbot claim` to assign the issue to yourself.
 +
 +There are also some abandoned PRs, marked with [`S-inactive-closed`].
 +Pretty often these PRs are nearly completed and just need some extra steps
 +(formatting, addressing review comments, ...) to be merged. If you want to
 +complete such a PR, please leave a comment in the PR and open a new one based
 +on it.
 +
 +Issues marked [`T-AST`] involve simple matching of the syntax tree structure,
 +and are generally easier than [`T-middle`] issues, which involve types
 +and resolved paths.
 +
 +[`T-AST`] issues will generally need you to match against a predefined syntax structure.
 +To figure out how this syntax structure is encoded in the AST, it is recommended to run
 +`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs].
 +Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 +But we can make it nest-less by using [if_chain] macro, [like this][nest-less].
 +
 +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
 +first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
 +Note that [`E-medium`] issues may require some knowledge of Clippy internals or some
 +debugging to find the actual problem behind the issue.
 +
 +[`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
 +lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
 +an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
 +
 +[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
 +[`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
 +[`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
 +[`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
 +[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
 +[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
 +[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
 +[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
 +[if_chain]: https://docs.rs/if_chain/*/if_chain
 +[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150
 +
 +## Writing code
 +
 +Have a look at the [docs for writing lints][adding_lints] for more details.
 +
 +If you want to add a new lint or change existing ones apart from bugfixing, it's
 +also a good idea to give the [stability guarantees][rfc_stability] and
 +[lint categories][rfc_lint_cats] sections of the [Clippy 1.0 RFC][clippy_rfc] a
 +quick read.
 +
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
 +[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
 +[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
 +
 +## Getting code-completion for rustc internals to work
 +
 +### IntelliJ Rust
 +Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals
 +using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not
 +available via a `rustup` component at the time of writing.
 +To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via
 +`git clone https://github.com/rust-lang/rust/`.
 +Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies
 +which `IntelliJ Rust` will be able to understand.
 +Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo
 +you just cloned.
 +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
- using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippys `Cargo.toml.`
- You will required a `nightly` toolchain with the `rustc-dev` component installed.
++Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
 +Just make sure to remove the dependencies again before finally making a pull request!
 +
 +[rustc_repo]: https://github.com/rust-lang/rust/
 +[IntelliJ_rust_homepage]: https://intellij-rust.github.io/
 +
 +### Rust Analyzer
 +As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals
- Currently there's a bug in `git-subtree` that prevents it from working properly
++using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippy's `Cargo.toml.`
++You will require a `nightly` toolchain with the `rustc-dev` component installed.
 +Make sure that in the `rust-analyzer` configuration, you set
 +```
 +{ "rust-analyzer.rustcSource": "discover" }
 +```
 +and
 +```
 +{ "rust-analyzer.updates.channel": "nightly" }
 +```
 +You should be able to see information on things like `Expr` or `EarlyContext` now if you hover them, also
 +a lot more type hints.
 +This will work with `rust-analyzer 2021-03-15` shipped in nightly `1.52.0-nightly (107896c32 2021-03-15)` or later.
 +
 +[ra_homepage]: https://rust-analyzer.github.io/
 +[6869]: https://github.com/rust-lang/rust-clippy/pull/6869
 +
 +## How Clippy works
 +
 +[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`].
 +For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this:
 +
 +```rust
 +// ./clippy_lints/src/lib.rs
 +
 +// ...
 +pub mod else_if_without_else;
 +// ...
 +
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    // ...
 +    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
 +    // ...
 +
 +    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +        // ...
 +        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +        // ...
 +    ]);
 +}
 +```
 +
 +The [`rustc_lint::LintStore`][`LintStore`] provides two methods to register lints:
 +[register_early_pass][reg_early_pass] and [register_late_pass][reg_late_pass]. Both take an object
 +that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in
 +every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev
 +update_lints`. When you are writing your own lint, you can use that script to save you some time.
 +
 +```rust
 +// ./clippy_lints/src/else_if_without_else.rs
 +
 +use rustc_lint::{EarlyLintPass, EarlyContext};
 +
 +// ...
 +
 +pub struct ElseIfWithoutElse;
 +
 +// ...
 +
 +impl EarlyLintPass for ElseIfWithoutElse {
 +    // ... the functions needed, to make the lint work
 +}
 +```
 +
 +The difference between `EarlyLintPass` and `LateLintPass` is that the methods of the `EarlyLintPass` trait only provide
 +AST information. The methods of the `LateLintPass` trait are executed after type checking and contain type information
 +via the `LateContext` parameter.
 +
 +That's why the `else_if_without_else` example uses the `register_early_pass` function. Because the
 +[actual lint logic][else_if_without_else] does not depend on any type information.
 +
 +[lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
 +[else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/4253aa7137cb7378acc96133c787e49a345c2b3c/clippy_lints/src/else_if_without_else.rs
 +[`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html
 +[reg_early_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_early_pass
 +[reg_late_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_late_pass
 +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
 +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
 +
 +## Syncing changes between Clippy and [`rust-lang/rust`]
 +
 +Clippy currently gets built with a pinned nightly version.
 +
 +In the `rust-lang/rust` repository, where rustc resides, there's a copy of Clippy
 +that compiler hackers modify from time to time to adapt to changes in the unstable
 +API of the compiler.
 +
 +We need to sync these changes back to this repository periodically, and the changes
 +made to this repository in the meantime also need to be synced to the `rust-lang/rust` repository.
 +
 +To avoid flooding the `rust-lang/rust` PR queue, this two-way sync process is done
 +in a bi-weekly basis if there's no urgent changes. This is done starting on the day of
 +the Rust stable release and then every other week. That way we guarantee that we keep
 +this repo up to date with the latest compiler API, and every feature in Clippy is available
 +for 2 weeks in nightly, before it can get to beta. For reference, the first sync
 +following this cadence was performed the 2020-08-27.
 +
 +This process is described in detail in the following sections. For general information
 +about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree].
 +
 +### Patching git-subtree to work with big repos
 +
++Currently, there's a bug in `git-subtree` that prevents it from working properly
 +with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale.
 +Before continuing with the following steps, we need to manually apply that fix to
 +our local copy of `git-subtree`.
 +
 +You can get the patched version of `git-subtree` from [here][gitgitgadget-pr].
 +Put this file under `/usr/lib/git-core` (taking a backup of the previous file)
 +and make sure it has the proper permissions:
 +
 +```bash
 +sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
 +sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +```
 +
 +_Note:_ The first time running `git subtree push` a cache has to be built. This
 +involves going through the complete Clippy history once. For this you have to
 +increase the stack limit though, which you can do with `ulimit -s 60000`.
 +Make sure to run the `ulimit` command from the same session you call git subtree.
 +
 +_Note:_ If you are a Debian user, `dash` is the shell used by default for scripts instead of `sh`.
 +This shell has a hardcoded recursion limit set to 1000. In order to make this process work,
 +you need to force the script to run `bash` instead. You can do this by editing the first
 +line of the `git-subtree` script and changing `sh` to `bash`.
 +
 +### Performing the sync from [`rust-lang/rust`] to Clippy
 +
 +Here is a TL;DR version of the sync process (all of the following commands have
 +to be run inside the `rust` directory):
 +
 +1. Clone the [`rust-lang/rust`] repository or make sure it is up to date.
 +2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
 +3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
 +    ```bash
 +    # Make sure to change `your-github-name` to your github name in the following command. Also be
 +    # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
 +    # because changes cannot be fast forwarded
 +    git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
 +    ```
 +
 +    _Note:_ This will directly push to the remote repository. You can also push
 +    to your local copy by replacing the remote address with `/path/to/rust-clippy`
 +    directory.
 +
 +    _Note:_ Most of the time you have to create a merge commit in the
 +    `rust-clippy` repo (this has to be done in the Clippy repo, not in the
 +    rust-copy of Clippy):
 +    ```bash
 +    git fetch origin && git fetch upstream
 +    git checkout sync-from-rust
 +    git merge upstream/master
 +    ```
 +4. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
 +   accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
 +   ~~annoy~~ ask them in the [Zulip] stream.)
 +
 +### Performing the sync from Clippy to [`rust-lang/rust`]
 +
 +All of the following commands have to be run inside the `rust` directory.
 +
 +1. Make sure Clippy itself is up-to-date by following the steps outlined in the previous
 +section if necessary.
 +
 +2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy:
 +    ```bash
 +    git checkout -b sync-from-clippy
 +    git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master
 +    ```
 +3. Open a PR to [`rust-lang/rust`]
 +
 +### Defining remotes
 +
 +You may want to define remotes, so you don't have to type out the remote
 +addresses on every sync. You can do this with the following commands (these
 +commands still have to be run inside the `rust` directory):
 +
 +```bash
 +# Set clippy-upstream remote for pulls
 +$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy
 +# Make sure to not push to the upstream repo
 +$ git remote set-url --push clippy-upstream DISABLED
 +# Set clippy-origin remote to your fork for pushes
 +$ git remote add clippy-origin git@github.com:your-github-name/rust-clippy
 +# Set a local remote
 +$ git remote add clippy-local /path/to/rust-clippy
 +```
 +
 +You can then sync with the remote names from above, e.g.:
 +
 +```bash
 +$ git subtree push -P src/tools/clippy clippy-local sync-from-rust
 +```
 +
 +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493
 +[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree
 +[`rust-lang/rust`]: https://github.com/rust-lang/rust
 +
 +## Issue and PR triage
 +
 +Clippy is following the [Rust triage procedure][triage] for issues and pull
 +requests.
 +
 +However, we are a smaller project with all contributors being volunteers
 +currently. Between writing new lints, fixing issues, reviewing pull requests and
 +responding to issues there may not always be enough time to stay on top of it
 +all.
 +
 +Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example
 +an ICE in a popular crate that many other crates depend on. We don't
 +want Clippy to crash on your code and we want it to be as reliable as the
 +suggestions from Rust compiler errors.
 +
 +We have prioritization labels and a sync-blocker label, which are described below.
 +- [P-low][p-low]: Requires attention (fix/response/evaluation) by a team member but isn't urgent.
 +- [P-medium][p-medium]: Should be addressed by a team member until the next sync.
 +- [P-high][p-high]: Should be immediately addressed and will require an out-of-cycle sync or a backport.
 +- [L-sync-blocker][l-sync-blocker]: An issue that "blocks" a sync.
 +Or rather: before the sync this should be addressed,
 +e.g. by removing a lint again, so it doesn't hit beta/stable.
 +
 +## Bors and Homu
 +
 +We use a bot powered by [Homu][homu] to help automate testing and landing of pull
 +requests in Clippy. The bot's username is @bors.
 +
 +You can find the Clippy bors queue [here][homu_queue].
 +
 +If you have @bors permissions, you can find an overview of the available
 +commands [here][homu_instructions].
 +
 +[triage]: https://forge.rust-lang.org/release/triage-procedure.html
 +[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash
 +[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug
 +[p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low
 +[p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium
 +[p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high
 +[l-sync-blocker]: https://github.com/rust-lang/rust-clippy/labels/L-sync-blocker
 +[homu]: https://github.com/rust-lang/homu
 +[homu_instructions]: https://bors.rust-lang.org/
 +[homu_queue]: https://bors.rust-lang.org/queue/clippy
 +
 +## Contributions
 +
 +Contributions to Clippy should be made in the form of GitHub pull requests. Each pull request will
 +be reviewed by a core contributor (someone with permission to land patches) and either landed in the
 +main tree or given feedback for changes that would be required.
 +
 +All code in this repository is under the [Apache-2.0] or the [MIT] license.
 +
 +<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
 +
 +[Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0
 +[MIT]: https://opensource.org/licenses/MIT
index 73b0167d363f62ef5d78b3c9ed91c22123e4df00,0000000000000000000000000000000000000000..1bbd89e7822e8a8f7d7d01c29b8302432c145ea4
mode 100644,000000..100644
--- /dev/null
@@@ -1,247 -1,0 +1,251 @@@
- value` mapping eg.
 +# Clippy
 +
 +[![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)
 +[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
 +
 +A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 +
 +[There are over 450 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::style`       | code that should be written in a more idiomatic way                                 | **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::pedantic`    | lints which are rather strict or have occasional false positives                    | allow         |
 +| `clippy::nursery`     | new lints that are still under development                                          | allow         |
 +| `clippy::cargo`       | lints for the cargo manifest                                                        | 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.
 +
 +Table of contents:
 +
 +*   [Usage instructions](#usage)
 +*   [Configuration](#configuration)
 +*   [Contributing](#contributing)
 +*   [License](#license)
 +
 +## Usage
 +
 +Below are instructions on how to use Clippy as a subcommand, compiled from source
 +or in Travis CI.
 +
 +### As a cargo subcommand (`cargo clippy`)
 +
 +One way to use Clippy is by installing Clippy through rustup as a cargo
 +subcommand.
 +
 +#### Step 1: Install Rustup
 +
 +You can install [Rustup](https://rustup.rs/) on supported platforms. This will help
 +us install Clippy and its dependencies.
 +
 +If you already have Rustup installed, update to ensure you have the latest
 +Rustup and compiler:
 +
 +```terminal
 +rustup update
 +```
 +
 +#### Step 2: Install Clippy
 +
 +Once you have rustup and the latest stable release (at least Rust 1.29) installed, run the following command:
 +
 +```terminal
 +rustup component add clippy
 +```
 +If it says that it can't find the `clippy` component, please run `rustup self update`.
 +
 +#### Step 3: Run Clippy
 +
 +Now you can run Clippy by invoking the following command:
 +
 +```terminal
 +cargo clippy
 +```
 +
 +#### Automatically applying Clippy suggestions
 +
 +Clippy can automatically apply some lint suggestions, just like the compiler.
 +
 +```terminal
 +cargo clippy --fix
 +```
 +
 +#### Workspaces
 +
 +All the usual workspace options should work with Clippy. For example the following command
 +will run Clippy on the `example` crate:
 +
 +```terminal
 +cargo clippy -p example
 +```
 +
 +As with `cargo check`, this includes dependencies that are members of the workspace, like path dependencies.
 +If you want to run Clippy **only** on the given crate, use the `--no-deps` option like this:
 +
 +```terminal
 +cargo clippy -p example -- --no-deps
 +```
 +
 +### As a rustc replacement (`clippy-driver`)
 +
 +Clippy can also be used in projects that do not use cargo. To do so, you will need to replace
 +your `rustc` compilation commands with `clippy-driver`. For example, if your project runs:
 +
 +```terminal
 +rustc --edition 2018 -Cpanic=abort foo.rs
 +```
 +
 +Then, to enable Clippy, you will need to call:
 +
 +```terminal
 +clippy-driver --edition 2018 -Cpanic=abort foo.rs
 +```
 +
 +Note that `rustc` will still run, i.e. it will still emit the output files it normally does.
 +
 +### Travis CI
 +
 +You can add Clippy to Travis CI in the same way you use it locally:
 +
 +```yml
 +language: rust
 +rust:
 +  - stable
 +  - beta
 +before_script:
 +  - rustup component add clippy
 +script:
 +  - cargo clippy
 +  # if you want the build job to fail when encountering warnings, use
 +  - cargo clippy -- -D warnings
 +  # in order to also check tests and non-default crate features, use
 +  - cargo clippy --all-targets --all-features -- -D warnings
 +  - cargo test
 +  # etc.
 +```
 +
 +Note that adding `-D warnings` will cause your build to fail if **any** warnings are found in your code.
 +That includes warnings found by rustc (e.g. `dead_code`, etc.). If you want to avoid this and only cause
 +an error for Clippy warnings, use `#![deny(clippy::all)]` in your code or `-D clippy::all` on the command
 +line. (You can swap `clippy::all` with the specific lint category you are targeting.)
 +
 +## Configuration
 +
 +Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable =
- This also works with lint groups. For example you
++value` mapping e.g.
 +
 +```toml
 +avoid-breaking-exported-api = false
 +blacklisted-names = ["toto", "tata", "titi"]
 +cognitive-complexity-threshold = 30
 +```
 +
 +See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
 +lints can be configured and the meaning of the variables.
 +
++Note that configuration changes will not apply for code that has already been compiled and cached under `./target/`;
++for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure that
++any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch.
++
 +To deactivate the “for further information visit *lint-link*” message you can
 +define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
 +
 +### Allowing/denying lints
 +
 +You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
 +
 +*   the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
 +    Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
 +
 +*   all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
 +    `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
 +    lints prone to false positives.
 +
 +*   only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
 +
 +*   `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
 +
 +Note: `allow` means to suppress the lint for your code. With `warn` the lint
 +will only emit a warning, while with `deny` the lint will emit an error, when
 +triggering for your code. An error causes clippy to exit with an error code, so
 +is useful in scripts like CI/CD.
 +
 +If you do not want to include your lint levels in your code, you can globally
 +enable/disable lints by passing extra flags to Clippy during the run:
 +
 +To allow `lint_name`, run
 +
 +```terminal
 +cargo clippy -- -A clippy::lint_name
 +```
 +
 +And to warn on `lint_name`, run
 +
 +```terminal
 +cargo clippy -- -W clippy::lint_name
 +```
 +
- Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly.
++This also works with lint groups. For example, you
 +can run Clippy with warnings for all lints enabled:
 +```terminal
 +cargo clippy -- -W clippy::pedantic
 +```
 +
 +If you care only about a single lint, you can allow all others and then explicitly warn on
 +the lint(s) you are interested in:
 +```terminal
 +cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
 +```
 +
 +### Specifying the minimum supported Rust version
 +
 +Projects that intend to support old versions of Rust can disable lints pertaining to newer features by
 +specifying the minimum supported Rust version (MSRV) in the clippy configuration file.
 +
 +```toml
 +msrv = "1.30.0"
 +```
 +
 +The MSRV can also be specified as an inner attribute, like below.
 +
 +```rust
 +#![feature(custom_inner_attributes)]
 +#![clippy::msrv = "1.30.0"]
 +
 +fn main() {
 +  ...
 +}
 +```
 +
 +You can also omit the patch version when specifying the MSRV, so `msrv = 1.30`
 +is equivalent to `msrv = 1.30.0`.
 +
++Note: `custom_inner_attributes` is an unstable feature, so it has to be enabled explicitly.
 +
 +Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv)
 +
 +## Contributing
 +
 +If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md).
 +
 +## License
 +
 +Copyright 2014-2021 The Rust Project Developers
 +
 +Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 +[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
 +<LICENSE-MIT or [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)>, at your
 +option. Files in the project may not be
 +copied, modified, or distributed except according to those terms.
index 12435eefbc4eeaf89816d09a1493c8049f85c61b,0000000000000000000000000000000000000000..5061c9d1eaf6f41a4a68b1c23a211b4ffb863c83
mode 100644,000000..100644
--- /dev/null
@@@ -1,134 -1,0 +1,134 @@@
-                 if is_approx_const(constant, &s, min_digits)
 +use clippy_utils::diagnostics::span_lint_and_help;
 +use clippy_utils::{meets_msrv, msrvs};
 +use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol;
 +use std::f64::consts as f64;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for floating point literals that approximate
 +    /// constants which are defined in
 +    /// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
 +    /// or
 +    /// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
 +    /// respectively, suggesting to use the predefined constant.
 +    ///
 +    /// ### Why is this bad?
 +    /// Usually, the definition in the standard library is more
 +    /// precise than what people come up with. If you find that your definition is
 +    /// actually more precise, please [file a Rust
 +    /// issue](https://github.com/rust-lang/rust/issues).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 3.14;
 +    /// let y = 1_f64 / x;
 +    /// ```
 +    /// Use predefined constants instead:
 +    /// ```rust
 +    /// let x = std::f32::consts::PI;
 +    /// let y = std::f64::consts::FRAC_1_PI;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub APPROX_CONSTANT,
 +    correctness,
 +    "the approximate of a known float constant (in `std::fXX::consts`)"
 +}
 +
 +// Tuples are of the form (constant, name, min_digits, msrv)
 +const KNOWN_CONSTS: [(f64, &str, usize, Option<RustcVersion>); 19] = [
 +    (f64::E, "E", 4, None),
 +    (f64::FRAC_1_PI, "FRAC_1_PI", 4, None),
 +    (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5, None),
 +    (f64::FRAC_2_PI, "FRAC_2_PI", 5, None),
 +    (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5, None),
 +    (f64::FRAC_PI_2, "FRAC_PI_2", 5, None),
 +    (f64::FRAC_PI_3, "FRAC_PI_3", 5, None),
 +    (f64::FRAC_PI_4, "FRAC_PI_4", 5, None),
 +    (f64::FRAC_PI_6, "FRAC_PI_6", 5, None),
 +    (f64::FRAC_PI_8, "FRAC_PI_8", 5, None),
 +    (f64::LN_2, "LN_2", 5, None),
 +    (f64::LN_10, "LN_10", 5, None),
 +    (f64::LOG2_10, "LOG2_10", 5, Some(msrvs::LOG2_10)),
 +    (f64::LOG2_E, "LOG2_E", 5, None),
 +    (f64::LOG10_2, "LOG10_2", 5, Some(msrvs::LOG10_2)),
 +    (f64::LOG10_E, "LOG10_E", 5, None),
 +    (f64::PI, "PI", 3, None),
 +    (f64::SQRT_2, "SQRT_2", 5, None),
 +    (f64::TAU, "TAU", 3, Some(msrvs::TAU)),
 +];
 +
 +pub struct ApproxConstant {
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl ApproxConstant {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self { msrv }
 +    }
 +
 +    fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
 +        match *lit {
 +            LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
 +                FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
 +                FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
 +            },
 +            LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) {
 +        let s = s.as_str();
 +        if s.parse::<f64>().is_ok() {
 +            for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
++                if is_approx_const(constant, s, min_digits)
 +                    && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv))
 +                {
 +                    span_lint_and_help(
 +                        cx,
 +                        APPROX_CONSTANT,
 +                        e.span,
 +                        &format!("approximate value of `{}::consts::{}` found", module, &name),
 +                        None,
 +                        "consider using the constant directly",
 +                    );
 +                    return;
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if let ExprKind::Lit(lit) = &e.kind {
 +            self.check_lit(cx, &lit.node, e);
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +/// Returns `false` if the number of significant figures in `value` are
 +/// less than `min_digits`; otherwise, returns true if `value` is equal
 +/// to `constant`, rounded to the number of digits present in `value`.
 +#[must_use]
 +fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
 +    if value.len() <= min_digits {
 +        false
 +    } else if constant.to_string().starts_with(value) {
 +        // The value is a truncated constant
 +        true
 +    } else {
 +        let round_const = format!("{:.*}", value.len() - 2, constant);
 +        value == round_const
 +    }
 +}
index 489945b513da4a975740c70031cb53cf9cd22e15,0000000000000000000000000000000000000000..0629674307ba77dd86ad61b4f042a1a726cdf8dd
mode 100644,000000..100644
--- /dev/null
@@@ -1,665 -1,0 +1,667 @@@
-                                             || extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "wildcard_imports")
-                                             || extract_clippy_lint(lint).map_or(false, |s| s.as_str() == "enum_glob_use")
 +//! checks for attributes
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::msrvs;
 +use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
 +use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv};
 +use if_chain::if_chain;
 +use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +use rustc_span::symbol::Symbol;
 +use semver::Version;
 +
 +static UNIX_SYSTEMS: &[&str] = &[
 +    "android",
 +    "dragonfly",
 +    "emscripten",
 +    "freebsd",
 +    "fuchsia",
 +    "haiku",
 +    "illumos",
 +    "ios",
 +    "l4re",
 +    "linux",
 +    "macos",
 +    "netbsd",
 +    "openbsd",
 +    "redox",
 +    "solaris",
 +    "vxworks",
 +];
 +
 +// NOTE: windows is excluded from the list because it's also a valid target family.
 +static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"];
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for items annotated with `#[inline(always)]`,
 +    /// unless the annotated function is empty or simply panics.
 +    ///
 +    /// ### Why is this bad?
 +    /// While there are valid uses of this annotation (and once
 +    /// you know when to use it, by all means `allow` this lint), it's a common
 +    /// newbie-mistake to pepper one's code with it.
 +    ///
 +    /// As a rule of thumb, before slapping `#[inline(always)]` on a function,
 +    /// measure if that additional function call really affects your runtime profile
 +    /// sufficiently to make up for the increase in compile time.
 +    ///
 +    /// ### Known problems
 +    /// False positives, big time. This lint is meant to be
 +    /// deactivated by everyone doing serious performance work. This means having
 +    /// done the measurement.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// #[inline(always)]
 +    /// fn not_quite_hot_code(..) { ... }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub INLINE_ALWAYS,
 +    pedantic,
 +    "use of `#[inline(always)]`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `extern crate` and `use` items annotated with
 +    /// lint attributes.
 +    ///
 +    /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`,
 +    /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and
 +    /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on
 +    /// `extern crate` items with a `#[macro_use]` attribute.
 +    ///
 +    /// ### Why is this bad?
 +    /// Lint attributes have no effect on crate imports. Most
 +    /// likely a `!` was forgotten.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// #[deny(dead_code)]
 +    /// extern crate foo;
 +    /// #[forbid(dead_code)]
 +    /// use foo::bar;
 +    ///
 +    /// // Ok
 +    /// #[allow(unused_imports)]
 +    /// use foo::baz;
 +    /// #[allow(unused_imports)]
 +    /// #[macro_use]
 +    /// extern crate baz;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USELESS_ATTRIBUTE,
 +    correctness,
 +    "use of lint attributes on `extern crate` items"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `#[deprecated]` annotations with a `since`
 +    /// field that is not a valid semantic version.
 +    ///
 +    /// ### Why is this bad?
 +    /// For checking the version of the deprecation, it must be
 +    /// a valid semver. Failing that, the contained information is useless.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// #[deprecated(since = "forever")]
 +    /// fn something_else() { /* ... */ }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DEPRECATED_SEMVER,
 +    correctness,
 +    "use of `#[deprecated(since = \"x\")]` where x is not semver"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for empty lines after outer attributes
 +    ///
 +    /// ### Why is this bad?
 +    /// Most likely the attribute was meant to be an inner attribute using a '!'.
 +    /// If it was meant to be an outer attribute, then the following item
 +    /// should not be separated by empty lines.
 +    ///
 +    /// ### Known problems
 +    /// Can cause false positives.
 +    ///
 +    /// From the clippy side it's difficult to detect empty lines between an attributes and the
 +    /// following item because empty lines and comments are not part of the AST. The parsing
 +    /// currently works for basic cases but is not perfect.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Good (as inner attribute)
 +    /// #![allow(dead_code)]
 +    ///
 +    /// fn this_is_fine() { }
 +    ///
 +    /// // Bad
 +    /// #[allow(dead_code)]
 +    ///
 +    /// fn not_quite_good_code() { }
 +    ///
 +    /// // Good (as outer attribute)
 +    /// #[allow(dead_code)]
 +    /// fn this_is_fine_too() { }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EMPTY_LINE_AFTER_OUTER_ATTR,
 +    nursery,
 +    "empty line after outer attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
 +    ///
 +    /// ### Why is this bad?
 +    /// Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
 +    /// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #![deny(clippy::restriction)]
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #![deny(clippy::as_conversions)]
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub BLANKET_CLIPPY_RESTRICTION_LINTS,
 +    suspicious,
 +    "enabling the complete restriction group"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
 +    /// with `#[rustfmt::skip]`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
 +    /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
 +    ///
 +    /// ### Known problems
 +    /// This lint doesn't detect crate level inner attributes, because they get
 +    /// processed before the PreExpansionPass lints get executed. See
 +    /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #[cfg_attr(rustfmt, rustfmt_skip)]
 +    /// fn main() { }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #[rustfmt::skip]
 +    /// fn main() { }
 +    /// ```
 +    #[clippy::version = "1.32.0"]
 +    pub DEPRECATED_CFG_ATTR,
 +    complexity,
 +    "usage of `cfg_attr(rustfmt)` instead of tool attributes"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for cfg attributes having operating systems used in target family position.
 +    ///
 +    /// ### Why is this bad?
 +    /// The configuration option will not be recognised and the related item will not be included
 +    /// by the conditional compilation engine.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #[cfg(linux)]
 +    /// fn conditional() { }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #[cfg(target_os = "linux")]
 +    /// fn conditional() { }
 +    /// ```
 +    ///
 +    /// Or:
 +    /// ```rust
 +    /// #[cfg(unix)]
 +    /// fn conditional() { }
 +    /// ```
 +    /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
 +    #[clippy::version = "1.45.0"]
 +    pub MISMATCHED_TARGET_OS,
 +    correctness,
 +    "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`"
 +}
 +
 +declare_lint_pass!(Attributes => [
 +    INLINE_ALWAYS,
 +    DEPRECATED_SEMVER,
 +    USELESS_ATTRIBUTE,
 +    BLANKET_CLIPPY_RESTRICTION_LINTS,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Attributes {
 +    fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
 +        if let Some(items) = &attr.meta_item_list() {
 +            if let Some(ident) = attr.ident() {
 +                if is_lint_level(ident.name) {
 +                    check_clippy_lint_names(cx, ident.name, items);
 +                }
 +                if items.is_empty() || !attr.has_name(sym::deprecated) {
 +                    return;
 +                }
 +                for item in items {
 +                    if_chain! {
 +                        if let NestedMetaItem::MetaItem(mi) = &item;
 +                        if let MetaItemKind::NameValue(lit) = &mi.kind;
 +                        if mi.has_name(sym::since);
 +                        then {
 +                            check_semver(cx, item.span(), lit);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        if is_relevant_item(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, attrs);
 +        }
 +        match item.kind {
 +            ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
 +                let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));
 +
 +                for attr in attrs {
 +                    if in_external_macro(cx.sess(), attr.span) {
 +                        return;
 +                    }
 +                    if let Some(lint_list) = &attr.meta_item_list() {
 +                        if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) {
 +                            // permit `unused_imports`, `deprecated`, `unreachable_pub`,
 +                            // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
 +                            // and `unused_imports` for `extern crate` items with `macro_use`
 +                            for lint in lint_list {
 +                                match item.kind {
 +                                    ItemKind::Use(..) => {
 +                                        if is_word(lint, sym!(unused_imports))
 +                                            || is_word(lint, sym::deprecated)
 +                                            || is_word(lint, sym!(unreachable_pub))
 +                                            || is_word(lint, sym!(unused))
++                                            || extract_clippy_lint(lint)
++                                                .map_or(false, |s| s.as_str() == "wildcard_imports")
++                                            || extract_clippy_lint(lint)
++                                                .map_or(false, |s| s.as_str() == "enum_glob_use")
 +                                        {
 +                                            return;
 +                                        }
 +                                    },
 +                                    ItemKind::ExternCrate(..) => {
 +                                        if is_word(lint, sym!(unused_imports)) && skip_unused_imports {
 +                                            return;
 +                                        }
 +                                        if is_word(lint, sym!(unused_extern_crates)) {
 +                                            return;
 +                                        }
 +                                    },
 +                                    _ => {},
 +                                }
 +                            }
 +                            let line_span = first_line_of_span(cx, attr.span);
 +
 +                            if let Some(mut sugg) = snippet_opt(cx, line_span) {
 +                                if sugg.contains("#[") {
 +                                    span_lint_and_then(
 +                                        cx,
 +                                        USELESS_ATTRIBUTE,
 +                                        line_span,
 +                                        "useless lint attribute",
 +                                        |diag| {
 +                                            sugg = sugg.replacen("#[", "#![", 1);
 +                                            diag.span_suggestion(
 +                                                line_span,
 +                                                "if you just forgot a `!`, use",
 +                                                sugg,
 +                                                Applicability::MaybeIncorrect,
 +                                            );
 +                                        },
 +                                    );
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if is_relevant_impl(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if is_relevant_trait(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
 +        }
 +    }
 +}
 +
 +/// Returns the lint name if it is clippy lint.
 +fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<Symbol> {
 +    if_chain! {
 +        if let Some(meta_item) = lint.meta_item();
 +        if meta_item.path.segments.len() > 1;
 +        if let tool_name = meta_item.path.segments[0].ident;
 +        if tool_name.name == sym::clippy;
 +        then {
 +            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
 +            return Some(lint_name);
 +        }
 +    }
 +    None
 +}
 +
 +fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) {
 +    for lint in items {
 +        if let Some(lint_name) = extract_clippy_lint(lint) {
 +            if lint_name.as_str() == "restriction" && name != sym::allow {
 +                span_lint_and_help(
 +                    cx,
 +                    BLANKET_CLIPPY_RESTRICTION_LINTS,
 +                    lint.span(),
 +                    "restriction lints are not meant to be all enabled",
 +                    None,
 +                    "try enabling only the lints you really need",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 +    if let ItemKind::Fn(_, _, eid) = item.kind {
 +        is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
 +    } else {
 +        true
 +    }
 +}
 +
 +fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
 +    match item.kind {
 +        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
 +        _ => false,
 +    }
 +}
 +
 +fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
 +    match item.kind {
 +        TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
 +        TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
 +            is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool {
 +    block.stmts.first().map_or(
 +        block
 +            .expr
 +            .as_ref()
 +            .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)),
 +        |stmt| match &stmt.kind {
 +            StmtKind::Local(_) => true,
 +            StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
 +            StmtKind::Item(_) => false,
 +        },
 +    )
 +}
 +
 +fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
 +    match &expr.kind {
 +        ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
 +        ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
 +        ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
 +        ExprKind::Call(path_expr, _) => {
 +            if let ExprKind::Path(qpath) = &path_expr.kind {
 +                typeck_results
 +                    .qpath_res(qpath, path_expr.hir_id)
 +                    .opt_def_id()
 +                    .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id))
 +            } else {
 +                true
 +            }
 +        },
 +        _ => true,
 +    }
 +}
 +
 +fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
 +    if span.from_expansion() {
 +        return;
 +    }
 +
 +    for attr in attrs {
 +        if let Some(values) = attr.meta_item_list() {
 +            if values.len() != 1 || !attr.has_name(sym::inline) {
 +                continue;
 +            }
 +            if is_word(&values[0], sym::always) {
 +                span_lint(
 +                    cx,
 +                    INLINE_ALWAYS,
 +                    attr.span,
 +                    &format!(
 +                        "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
 +                        name
 +                    ),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) {
 +    if let LitKind::Str(is, _) = lit.kind {
 +        if Version::parse(is.as_str()).is_ok() {
 +            return;
 +        }
 +    }
 +    span_lint(
 +        cx,
 +        DEPRECATED_SEMVER,
 +        span,
 +        "the since field must contain a semver-compliant version",
 +    );
 +}
 +
 +fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
 +    if let NestedMetaItem::MetaItem(mi) = &nmi {
 +        mi.is_word() && mi.has_name(expected)
 +    } else {
 +        false
 +    }
 +}
 +
 +pub struct EarlyAttributes {
 +    pub msrv: Option<RustcVersion>,
 +}
 +
 +impl_lint_pass!(EarlyAttributes => [
 +    DEPRECATED_CFG_ATTR,
 +    MISMATCHED_TARGET_OS,
 +    EMPTY_LINE_AFTER_OUTER_ATTR,
 +]);
 +
 +impl EarlyLintPass for EarlyAttributes {
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
 +        check_empty_line_after_outer_attr(cx, item);
 +    }
 +
 +    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
 +        check_deprecated_cfg_attr(cx, attr, self.msrv);
 +        check_mismatched_target_os(cx, attr);
 +    }
 +
 +    extract_msrv_attr!(EarlyContext);
 +}
 +
 +fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
 +    for attr in &item.attrs {
 +        let attr_item = if let AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr
 +        } else {
 +            return;
 +        };
 +
 +        if attr.style == AttrStyle::Outer {
 +            if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
 +                return;
 +            }
 +
 +            let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
 +            let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());
 +
 +            if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
 +                let lines = snippet.split('\n').collect::<Vec<_>>();
 +                let lines = without_block_comments(lines);
 +
 +                if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
 +                    span_lint(
 +                        cx,
 +                        EMPTY_LINE_AFTER_OUTER_ATTR,
 +                        begin_of_attr_to_item,
 +                        "found an empty line after an outer attribute. \
 +                        Perhaps you forgot to add a `!` to make it an inner attribute?",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
 +    if_chain! {
 +        if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES);
 +        // check cfg_attr
 +        if attr.has_name(sym::cfg_attr);
 +        if let Some(items) = attr.meta_item_list();
 +        if items.len() == 2;
 +        // check for `rustfmt`
 +        if let Some(feature_item) = items[0].meta_item();
 +        if feature_item.has_name(sym::rustfmt);
 +        // check for `rustfmt_skip` and `rustfmt::skip`
 +        if let Some(skip_item) = &items[1].meta_item();
 +        if skip_item.has_name(sym!(rustfmt_skip)) ||
 +            skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip;
 +        // Only lint outer attributes, because custom inner attributes are unstable
 +        // Tracking issue: https://github.com/rust-lang/rust/issues/54726
 +        if attr.style == AttrStyle::Outer;
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                DEPRECATED_CFG_ATTR,
 +                attr.span,
 +                "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes",
 +                "use",
 +                "#[rustfmt::skip]".to_string(),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
 +    fn find_os(name: &str) -> Option<&'static str> {
 +        UNIX_SYSTEMS
 +            .iter()
 +            .chain(NON_UNIX_SYSTEMS.iter())
 +            .find(|&&os| os == name)
 +            .copied()
 +    }
 +
 +    fn is_unix(name: &str) -> bool {
 +        UNIX_SYSTEMS.iter().any(|&os| os == name)
 +    }
 +
 +    fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> {
 +        let mut mismatched = Vec::new();
 +
 +        for item in items {
 +            if let NestedMetaItem::MetaItem(meta) = item {
 +                match &meta.kind {
 +                    MetaItemKind::List(list) => {
 +                        mismatched.extend(find_mismatched_target_os(list));
 +                    },
 +                    MetaItemKind::Word => {
 +                        if_chain! {
 +                            if let Some(ident) = meta.ident();
 +                            if let Some(os) = find_os(ident.name.as_str());
 +                            then {
 +                                mismatched.push((os, ident.span));
 +                            }
 +                        }
 +                    },
 +                    MetaItemKind::NameValue(..) => {},
 +                }
 +            }
 +        }
 +
 +        mismatched
 +    }
 +
 +    if_chain! {
 +        if attr.has_name(sym::cfg);
 +        if let Some(list) = attr.meta_item_list();
 +        let mismatched = find_mismatched_target_os(&list);
 +        if !mismatched.is_empty();
 +        then {
 +            let mess = "operating system used in target family position";
 +
 +            span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
 +                // Avoid showing the unix suggestion multiple times in case
 +                // we have more than one mismatch for unix-like systems
 +                let mut unix_suggested = false;
 +
 +                for (os, span) in mismatched {
 +                    let sugg = format!("target_os = \"{}\"", os);
 +                    diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
 +
 +                    if !unix_suggested && is_unix(os) {
 +                        diag.help("did you mean `unix`?");
 +                        unix_suggested = true;
 +                    }
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +fn is_lint_level(symbol: Symbol) -> bool {
 +    matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid)
 +}
index 9ed359922fd4da4f4e80fa34dd9f99e72074e38a,0000000000000000000000000000000000000000..1915d990c126c1e4b990104b1fce603afac4fa53
mode 100644,000000..100644
--- /dev/null
@@@ -1,118 -1,0 +1,119 @@@
-                     let num_lit = NumericLiteral::from_lit_kind(&src, &lit.node).unwrap();
-                     lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::numeric_literal::NumericLiteral;
 +use clippy_utils::source::snippet_opt;
 +use if_chain::if_chain;
 +use rustc_ast::{LitFloatType, LitIntType, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, Lit, UnOp};
 +use rustc_lint::{LateContext, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
 +
 +use super::UNNECESSARY_CAST;
 +
 +pub(super) fn check(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    cast_expr: &Expr<'_>,
 +    cast_from: Ty<'_>,
 +    cast_to: Ty<'_>,
 +) -> bool {
 +    if let Some(lit) = get_numeric_literal(cast_expr) {
 +        let literal_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
 +
 +        if_chain! {
 +            if let LitKind::Int(n, _) = lit.node;
 +            if let Some(src) = snippet_opt(cx, lit.span);
 +            if cast_to.is_floating_point();
 +            if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
 +            let from_nbits = 128 - n.leading_zeros();
 +            let to_nbits = fp_ty_mantissa_nbits(cast_to);
 +            if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
 +            then {
 +                let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
 +                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
 +                return true
 +            }
 +        }
 +
 +        match lit.node {
 +            LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
 +                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
 +            },
 +            LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
 +                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
 +            },
 +            LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
 +            LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_))
 +            | LitKind::Float(_, LitFloatType::Suffixed(_))
 +                if cast_from.kind() == cast_to.kind() =>
 +            {
 +                if let Some(src) = snippet_opt(cx, lit.span) {
++                    if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
++                        lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
++                    }
 +                }
 +            },
 +            _ => {
 +                if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        UNNECESSARY_CAST,
 +                        expr.span,
 +                        &format!(
 +                            "casting to the same type is unnecessary (`{}` -> `{}`)",
 +                            cast_from, cast_to
 +                        ),
 +                        "try",
 +                        literal_str,
 +                        Applicability::MachineApplicable,
 +                    );
 +                    return true;
 +                }
 +            },
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
 +    span_lint_and_sugg(
 +        cx,
 +        UNNECESSARY_CAST,
 +        expr.span,
 +        &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
 +        "try",
 +        format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
 +    match expr.kind {
 +        ExprKind::Lit(ref lit) => Some(lit),
 +        ExprKind::Unary(UnOp::Neg, e) => {
 +            if let ExprKind::Lit(ref lit) = e.kind {
 +                Some(lit)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +/// Returns the mantissa bits wide of a fp type.
 +/// Will return 0 if the type is not a fp
 +fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
 +    match typ.kind() {
 +        ty::Float(FloatTy::F32) => 23,
 +        ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
 +        _ => 0,
 +    }
 +}
 +
 +fn is_unary_neg(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
 +}
index 689ac6184bffb1d7b5762a5e6dc9bc47474b5d08,0000000000000000000000000000000000000000..4f89e5674306817ab83b3f3f791e80716aed6c4c
mode 100644,000000..100644
--- /dev/null
@@@ -1,291 -1,0 +1,297 @@@
- use clippy_utils::str_utils::{self, count_match_end, count_match_start};
- use rustc_hir::{EnumDef, Item, ItemKind};
 +//! lint on enum variants that are prefixed or suffixed by the same characters
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::source::is_present_in_source;
- fn check_variant(
-     cx: &LateContext<'_>,
-     threshold: u64,
-     def: &EnumDef<'_>,
-     item_name: &str,
-     item_name_chars: usize,
-     span: Span,
- ) {
++use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
++use rustc_hir::{EnumDef, Item, ItemKind, Variant};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::Symbol;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects enumeration variants that are prefixed or suffixed
 +    /// by the same characters.
 +    ///
 +    /// ### Why is this bad?
 +    /// Enumeration variant names should specify their variant,
 +    /// not repeat the enumeration name.
 +    ///
++    /// ### Limitations
++    /// Characters with no casing will be considered when comparing prefixes/suffixes
++    /// This applies to numbers and non-ascii characters without casing
++    /// e.g. `Foo1` and `Foo2` is considered to have different prefixes
++    /// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
++    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForestCake,
 +    ///     HummingbirdCake,
 +    ///     BattenbergCake,
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForest,
 +    ///     Hummingbird,
 +    ///     Battenberg,
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ENUM_VARIANT_NAMES,
 +    style,
 +    "enums where all variants share a prefix/postfix"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects type names that are prefixed or suffixed by the
 +    /// containing module's name.
 +    ///
 +    /// ### Why is this bad?
 +    /// It requires the user to type the module name twice.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForestCake;
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForest;
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.33.0"]
 +    pub MODULE_NAME_REPETITIONS,
 +    pedantic,
 +    "type names prefixed/postfixed with their containing module's name"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for modules that have the same name as their
 +    /// parent module
 +    ///
 +    /// ### Why is this bad?
 +    /// A typical beginner mistake is to have `mod foo;` and
 +    /// again `mod foo { ..
 +    /// }` in `foo.rs`.
 +    /// The expectation is that items inside the inner `mod foo { .. }` are then
 +    /// available
 +    /// through `foo::x`, but they are only available through
 +    /// `foo::foo::x`.
 +    /// If this is done on purpose, it would be better to choose a more
 +    /// representative module name.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // lib.rs
 +    /// mod foo;
 +    /// // foo.rs
 +    /// mod foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MODULE_INCEPTION,
 +    style,
 +    "modules that have the same name as their parent module"
 +}
 +
 +pub struct EnumVariantNames {
 +    modules: Vec<(Symbol, String)>,
 +    threshold: u64,
 +    avoid_breaking_exported_api: bool,
 +}
 +
 +impl EnumVariantNames {
 +    #[must_use]
 +    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
 +        Self {
 +            modules: Vec::new(),
 +            threshold,
 +            avoid_breaking_exported_api,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(EnumVariantNames => [
 +    ENUM_VARIANT_NAMES,
 +    MODULE_NAME_REPETITIONS,
 +    MODULE_INCEPTION
 +]);
 +
-         let name = var.ident.name.as_str();
-         if count_match_start(item_name, &name).char_count == item_name_chars
-             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
-             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
-         {
-             span_lint(
-                 cx,
-                 ENUM_VARIANT_NAMES,
-                 var.span,
-                 "variant name starts with the enum's name",
-             );
-         }
-         if count_match_end(item_name, &name).char_count == item_name_chars {
-             span_lint(
-                 cx,
-                 ENUM_VARIANT_NAMES,
-                 var.span,
-                 "variant name ends with the enum's name",
-             );
-         }
-     }
-     let first = def.variants[0].ident.name.as_str();
-     let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
-     let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
-     for var in def.variants {
++fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
++    let name = variant.ident.name.as_str();
++    let item_name_chars = item_name.chars().count();
++
++    if count_match_start(item_name, name).char_count == item_name_chars
++        && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
++        && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
++    {
++        span_lint(
++            cx,
++            ENUM_VARIANT_NAMES,
++            variant.span,
++            "variant name starts with the enum's name",
++        );
++    }
++}
++
++fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
++    let name = variant.ident.name.as_str();
++    let item_name_chars = item_name.chars().count();
++
++    if count_match_end(item_name, name).char_count == item_name_chars {
++        span_lint(
++            cx,
++            ENUM_VARIANT_NAMES,
++            variant.span,
++            "variant name ends with the enum's name",
++        );
++    }
++}
++
++fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_name: &str, span: Span) {
 +    if (def.variants.len() as u64) < threshold {
 +        return;
 +    }
++
++    let first = &def.variants[0].ident.name.as_str();
++    let mut pre = camel_case_split(first);
++    let mut post = pre.clone();
++    post.reverse();
 +    for var in def.variants {
-         let pre_match = count_match_start(pre, &name).byte_count;
-         pre = &pre[..pre_match];
-         let pre_camel = str_utils::camel_case_until(pre).byte_index;
-         pre = &pre[..pre_camel];
-         while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
-             if next.is_numeric() {
-                 return;
-             }
-             if next.is_lowercase() {
-                 let last = pre.len() - last.len_utf8();
-                 let last_camel = str_utils::camel_case_until(&pre[..last]);
-                 pre = &pre[..last_camel.byte_index];
-             } else {
-                 break;
-             }
-         }
++        check_enum_start(cx, item_name, var);
++        check_enum_end(cx, item_name, var);
 +        let name = var.ident.name.as_str();
 +
-         let post_match = count_match_end(post, &name);
-         let post_end = post.len() - post_match.byte_count;
-         post = &post[post_end..];
-         let post_camel = str_utils::camel_case_start(post);
-         post = &post[post_camel.byte_index..];
++        let variant_split = camel_case_split(name);
 +
-         (false, _) => ("pre", pre),
-         (true, false) => ("post", post),
++        pre = pre
++            .iter()
++            .zip(variant_split.iter())
++            .take_while(|(a, b)| a == b)
++            .map(|e| *e.0)
++            .collect();
++        post = post
++            .iter()
++            .zip(variant_split.iter().rev())
++            .take_while(|(a, b)| a == b)
++            .map(|e| *e.0)
++            .collect();
 +    }
 +    let (what, value) = match (pre.is_empty(), post.is_empty()) {
 +        (true, true) => return,
-         let item_name_chars = item_name.chars().count();
-         let item_camel = to_camel_case(&item_name);
++        (false, _) => ("pre", pre.join("")),
++        (true, false) => {
++            post.reverse();
++            ("post", post.join(""))
++        },
 +    };
 +    span_lint_and_help(
 +        cx,
 +        ENUM_VARIANT_NAMES,
 +        span,
 +        &format!("all variants have the same {}fix: `{}`", what, value),
 +        None,
 +        &format!(
 +            "remove the {}fixes and use full paths to \
 +             the variants instead of glob imports",
 +            what
 +        ),
 +    );
 +}
 +
 +#[must_use]
 +fn to_camel_case(item_name: &str) -> String {
 +    let mut s = String::new();
 +    let mut up = true;
 +    for c in item_name.chars() {
 +        if c.is_uppercase() {
 +            // we only turn snake case text into CamelCase
 +            return item_name.to_string();
 +        }
 +        if c == '_' {
 +            up = true;
 +            continue;
 +        }
 +        if up {
 +            up = false;
 +            s.extend(c.to_uppercase());
 +        } else {
 +            s.push(c);
 +        }
 +    }
 +    s
 +}
 +
 +impl LateLintPass<'_> for EnumVariantNames {
 +    fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
 +        let last = self.modules.pop();
 +        assert!(last.is_some());
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        let item_name = item.ident.name.as_str();
-                 check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
++        let item_camel = to_camel_case(item_name);
 +        if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
 +            if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
 +                // constants don't have surrounding modules
 +                if !mod_camel.is_empty() {
 +                    if mod_name == &item.ident.name {
 +                        if let ItemKind::Mod(..) = item.kind {
 +                            span_lint(
 +                                cx,
 +                                MODULE_INCEPTION,
 +                                item.span,
 +                                "module has the same name as its containing module",
 +                            );
 +                        }
 +                    }
 +                    // The `module_name_repetitions` lint should only trigger if the item has the module in its
 +                    // name. Having the same name is accepted.
 +                    if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
 +                        let matching = count_match_start(mod_camel, &item_camel);
 +                        let rmatching = count_match_end(mod_camel, &item_camel);
 +                        let nchars = mod_camel.chars().count();
 +
 +                        let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
 +
 +                        if matching.char_count == nchars {
 +                            match item_camel.chars().nth(nchars) {
 +                                Some(c) if is_word_beginning(c) => span_lint(
 +                                    cx,
 +                                    MODULE_NAME_REPETITIONS,
 +                                    item.span,
 +                                    "item name starts with its containing module's name",
 +                                ),
 +                                _ => (),
 +                            }
 +                        }
 +                        if rmatching.char_count == nchars {
 +                            span_lint(
 +                                cx,
 +                                MODULE_NAME_REPETITIONS,
 +                                item.span,
 +                                "item name ends with its containing module's name",
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +        if let ItemKind::Enum(ref def, _) = item.kind {
 +            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
++                check_variant(cx, self.threshold, def, item_name, item.span);
 +            }
 +        }
 +        self.modules.push((item.ident.name, item_camel));
 +    }
 +}
index 6903073fbcd85760aaba967cf135d9f37d0165d8,0000000000000000000000000000000000000000..7a4397a7b746714ac8cd70d26d4a797e76976f13
mode 100644,000000..100644
--- /dev/null
@@@ -1,179 -1,0 +1,179 @@@
-                 let digits = count_digits(&sym_str);
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::numeric_literal;
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, LitFloatType, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, FloatTy};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use std::fmt;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for float literals with a precision greater
 +    /// than that supported by the underlying type.
 +    ///
 +    /// ### Why is this bad?
 +    /// Rust will truncate the literal silently.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let v: f32 = 0.123_456_789_9;
 +    /// println!("{}", v); //  0.123_456_789
 +    ///
 +    /// // Good
 +    /// let v: f64 = 0.123_456_789_9;
 +    /// println!("{}", v); //  0.123_456_789_9
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EXCESSIVE_PRECISION,
 +    style,
 +    "excessive precision for float literal"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for whole number float literals that
 +    /// cannot be represented as the underlying type without loss.
 +    ///
 +    /// ### Why is this bad?
 +    /// Rust will silently lose precision during
 +    /// conversion to a float.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let _: f32 = 16_777_217.0; // 16_777_216.0
 +    ///
 +    /// // Good
 +    /// let _: f32 = 16_777_216.0;
 +    /// let _: f64 = 16_777_217.0;
 +    /// ```
 +    #[clippy::version = "1.43.0"]
 +    pub LOSSY_FLOAT_LITERAL,
 +    restriction,
 +    "lossy whole number float literals"
 +}
 +
 +declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
 +
 +impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        let ty = cx.typeck_results().expr_ty(expr);
 +        if_chain! {
 +            if let ty::Float(fty) = *ty.kind();
 +            if let hir::ExprKind::Lit(ref lit) = expr.kind;
 +            if let LitKind::Float(sym, lit_float_ty) = lit.node;
 +            then {
 +                let sym_str = sym.as_str();
 +                let formatter = FloatFormat::new(sym_str);
 +                // Try to bail out if the float is for sure fine.
 +                // If its within the 2 decimal digits of being out of precision we
 +                // check if the parsed representation is the same as the string
 +                // since we'll need the truncated string anyway.
++                let digits = count_digits(sym_str);
 +                let max = max_digits(fty);
 +                let type_suffix = match lit_float_ty {
 +                    LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
 +                    LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
 +                    LitFloatType::Unsuffixed => None
 +                };
 +                let (is_whole, mut float_str) = match fty {
 +                    FloatTy::F32 => {
 +                        let value = sym_str.parse::<f32>().unwrap();
 +
 +                        (value.fract() == 0.0, formatter.format(value))
 +                    },
 +                    FloatTy::F64 => {
 +                        let value = sym_str.parse::<f64>().unwrap();
 +
 +                        (value.fract() == 0.0, formatter.format(value))
 +                    },
 +                };
 +
 +                if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') {
 +                    // Normalize the literal by stripping the fractional portion
 +                    if sym_str.split('.').next().unwrap() != float_str {
 +                        // If the type suffix is missing the suggestion would be
 +                        // incorrectly interpreted as an integer so adding a `.0`
 +                        // suffix to prevent that.
 +                        if type_suffix.is_none() {
 +                            float_str.push_str(".0");
 +                        }
 +
 +                        span_lint_and_sugg(
 +                            cx,
 +                            LOSSY_FLOAT_LITERAL,
 +                            expr.span,
 +                            "literal cannot be represented as the underlying type without loss of precision",
 +                            "consider changing the type or replacing it with",
 +                            numeric_literal::format(&float_str, type_suffix, true),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    }
 +                } else if digits > max as usize && float_str.len() < sym_str.len() {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        EXCESSIVE_PRECISION,
 +                        expr.span,
 +                        "float has excessive precision",
 +                        "consider changing the type or truncating it to",
 +                        numeric_literal::format(&float_str, type_suffix, true),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[must_use]
 +fn max_digits(fty: FloatTy) -> u32 {
 +    match fty {
 +        FloatTy::F32 => f32::DIGITS,
 +        FloatTy::F64 => f64::DIGITS,
 +    }
 +}
 +
 +/// Counts the digits excluding leading zeros
 +#[must_use]
 +fn count_digits(s: &str) -> usize {
 +    // Note that s does not contain the f32/64 suffix, and underscores have been stripped
 +    s.chars()
 +        .filter(|c| *c != '-' && *c != '.')
 +        .take_while(|c| *c != 'e' && *c != 'E')
 +        .fold(0, |count, c| {
 +            // leading zeros
 +            if c == '0' && count == 0 { count } else { count + 1 }
 +        })
 +}
 +
 +enum FloatFormat {
 +    LowerExp,
 +    UpperExp,
 +    Normal,
 +}
 +impl FloatFormat {
 +    #[must_use]
 +    fn new(s: &str) -> Self {
 +        s.chars()
 +            .find_map(|x| match x {
 +                'e' => Some(Self::LowerExp),
 +                'E' => Some(Self::UpperExp),
 +                _ => None,
 +            })
 +            .unwrap_or(Self::Normal)
 +    }
 +    fn format<T>(&self, f: T) -> String
 +    where
 +        T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
 +    {
 +        match self {
 +            Self::LowerExp => format!("{:e}", f),
 +            Self::UpperExp => format!("{:E}", f),
 +            Self::Normal => format!("{}", f),
 +        }
 +    }
 +}
index a70e58c9c3a5efdd3316e553c334fd6df6d7d7b0,0000000000000000000000000000000000000000..6dcbaf68dfdbcb3787087603e2cba3bb00a94fef
mode 100644,000000..100644
--- /dev/null
@@@ -1,712 -1,0 +1,738 @@@
-                 return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, ".."), Sugg::hir(cx, rmul_lhs, "..")));
 +use clippy_utils::consts::{
 +    constant, constant_simple, Constant,
 +    Constant::{Int, F32, F64},
 +};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher;
 +use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +
 +use rustc_ast::ast;
 +use std::f32::consts as f32_consts;
 +use std::f64::consts as f64_consts;
 +use sugg::Sugg;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Looks for floating-point expressions that
 +    /// can be expressed using built-in methods to improve accuracy
 +    /// at the cost of performance.
 +    ///
 +    /// ### Why is this bad?
 +    /// Negatively impacts accuracy.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = 3f32;
 +    /// let _ = a.powf(1.0 / 3.0);
 +    /// let _ = (1.0 + a).ln();
 +    /// let _ = a.exp() - 1.0;
 +    /// ```
 +    ///
 +    /// is better expressed as
 +    ///
 +    /// ```rust
 +    /// let a = 3f32;
 +    /// let _ = a.cbrt();
 +    /// let _ = a.ln_1p();
 +    /// let _ = a.exp_m1();
 +    /// ```
 +    #[clippy::version = "1.43.0"]
 +    pub IMPRECISE_FLOPS,
 +    nursery,
 +    "usage of imprecise floating point operations"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Looks for floating-point expressions that
 +    /// can be expressed using built-in methods to improve both
 +    /// accuracy and performance.
 +    ///
 +    /// ### Why is this bad?
 +    /// Negatively impacts accuracy and performance.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::f32::consts::E;
 +    ///
 +    /// let a = 3f32;
 +    /// let _ = (2f32).powf(a);
 +    /// let _ = E.powf(a);
 +    /// let _ = a.powf(1.0 / 2.0);
 +    /// let _ = a.log(2.0);
 +    /// let _ = a.log(10.0);
 +    /// let _ = a.log(E);
 +    /// let _ = a.powf(2.0);
 +    /// let _ = a * 2.0 + 4.0;
 +    /// let _ = if a < 0.0 {
 +    ///     -a
 +    /// } else {
 +    ///     a
 +    /// };
 +    /// let _ = if a < 0.0 {
 +    ///     a
 +    /// } else {
 +    ///     -a
 +    /// };
 +    /// ```
 +    ///
 +    /// is better expressed as
 +    ///
 +    /// ```rust
 +    /// use std::f32::consts::E;
 +    ///
 +    /// let a = 3f32;
 +    /// let _ = a.exp2();
 +    /// let _ = a.exp();
 +    /// let _ = a.sqrt();
 +    /// let _ = a.log2();
 +    /// let _ = a.log10();
 +    /// let _ = a.ln();
 +    /// let _ = a.powi(2);
 +    /// let _ = a.mul_add(2.0, 4.0);
 +    /// let _ = a.abs();
 +    /// let _ = -a.abs();
 +    /// ```
 +    #[clippy::version = "1.43.0"]
 +    pub SUBOPTIMAL_FLOPS,
 +    nursery,
 +    "usage of sub-optimal floating point operations"
 +}
 +
 +declare_lint_pass!(FloatingPointArithmetic => [
 +    IMPRECISE_FLOPS,
 +    SUBOPTIMAL_FLOPS
 +]);
 +
 +// Returns the specialized log method for a given base if base is constant
 +// and is one of 2, 10 and e
 +fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
 +    if let Some((value, _)) = constant(cx, cx.typeck_results(), base) {
 +        if F32(2.0) == value || F64(2.0) == value {
 +            return Some("log2");
 +        } else if F32(10.0) == value || F64(10.0) == value {
 +            return Some("log10");
 +        } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
 +            return Some("ln");
 +        }
 +    }
 +
 +    None
 +}
 +
 +// Adds type suffixes and parenthesis to method receivers if necessary
 +fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Sugg<'a> {
 +    let mut suggestion = Sugg::hir(cx, expr, "..");
 +
 +    if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind {
 +        expr = inner_expr;
 +    }
 +
 +    if_chain! {
 +        // if the expression is a float literal and it is unsuffixed then
 +        // add a suffix so the suggestion is valid and unambiguous
 +        if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind();
 +        if let ExprKind::Lit(lit) = &expr.kind;
 +        if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
 +        then {
 +            let op = format!(
 +                "{}{}{}",
 +                suggestion,
 +                // Check for float literals without numbers following the decimal
 +                // separator such as `2.` and adds a trailing zero
 +                if sym.as_str().ends_with('.') {
 +                    "0"
 +                } else {
 +                    ""
 +                },
 +                float_ty.name_str()
 +            ).into();
 +
 +            suggestion = match suggestion {
 +                Sugg::MaybeParen(_) => Sugg::MaybeParen(op),
 +                _ => Sugg::NonParen(op)
 +            };
 +        }
 +    }
 +
 +    suggestion.maybe_par()
 +}
 +
 +fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 +    if let Some(method) = get_specialized_log_method(cx, &args[1]) {
 +        span_lint_and_sugg(
 +            cx,
 +            SUBOPTIMAL_FLOPS,
 +            expr.span,
 +            "logarithm for bases 2, 10 and e can be computed more accurately",
 +            "consider using",
 +            format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
 +// suggest usage of `(x + (y - 1)).ln_1p()` instead
 +fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 +    if let ExprKind::Binary(
 +        Spanned {
 +            node: BinOpKind::Add, ..
 +        },
 +        lhs,
 +        rhs,
 +    ) = &args[0].kind
 +    {
 +        let recv = match (
 +            constant(cx, cx.typeck_results(), lhs),
 +            constant(cx, cx.typeck_results(), rhs),
 +        ) {
 +            (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs,
 +            (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs,
 +            _ => return,
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            IMPRECISE_FLOPS,
 +            expr.span,
 +            "ln(1 + x) can be computed more accurately",
 +            "consider using",
 +            format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +// Returns an integer if the float constant is a whole number and it can be
 +// converted to an integer without loss of precision. For now we only check
 +// ranges [-16777215, 16777216) for type f32 as whole number floats outside
 +// this range are lossy and ambiguous.
 +#[allow(clippy::cast_possible_truncation)]
 +fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 +    match value {
 +        F32(num) if num.fract() == 0.0 => {
 +            if (-16_777_215.0..16_777_216.0).contains(num) {
 +                Some(num.round() as i32)
 +            } else {
 +                None
 +            }
 +        },
 +        F64(num) if num.fract() == 0.0 => {
 +            if (-2_147_483_648.0..2_147_483_648.0).contains(num) {
 +                Some(num.round() as i32)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 +    // Check receiver
 +    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
 +        let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
 +            "exp"
 +        } else if F32(2.0) == value || F64(2.0) == value {
 +            "exp2"
 +        } else {
 +            return;
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            SUBOPTIMAL_FLOPS,
 +            expr.span,
 +            "exponent for bases 2 and e can be computed more accurately",
 +            "consider using",
 +            format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +
 +    // Check argument
 +    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
 +        let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
 +            (
 +                SUBOPTIMAL_FLOPS,
 +                "square-root of a number can be computed more efficiently and accurately",
 +                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")),
 +            )
 +        } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
 +            (
 +                IMPRECISE_FLOPS,
 +                "cube-root of a number can be computed more accurately",
 +                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")),
 +            )
 +        } else if let Some(exponent) = get_integer_from_float_constant(&value) {
 +            (
 +                SUBOPTIMAL_FLOPS,
 +                "exponentiation with integer powers can be computed more efficiently",
 +                format!(
 +                    "{}.powi({})",
 +                    Sugg::hir(cx, &args[0], ".."),
 +                    numeric_literal::format(&exponent.to_string(), None, false)
 +                ),
 +            )
 +        } else {
 +            return;
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            lint,
 +            expr.span,
 +            help,
 +            "consider using",
 +            suggestion,
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 +    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
 +        if value == Int(2) {
 +            if let Some(parent) = get_parent_expr(cx, expr) {
 +                if let Some(grandparent) = get_parent_expr(cx, parent) {
 +                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
 +                        if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
 +                            return;
 +                        }
 +                    }
 +                }
 +
 +                if let ExprKind::Binary(
 +                    Spanned {
 +                        node: BinOpKind::Add, ..
 +                    },
 +                    lhs,
 +                    rhs,
 +                ) = parent.kind
 +                {
 +                    let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
 +
 +                    span_lint_and_sugg(
 +                        cx,
 +                        SUBOPTIMAL_FLOPS,
 +                        parent.span,
 +                        "multiply and add expressions can be calculated more efficiently and accurately",
 +                        "consider using",
 +                        format!(
 +                            "{}.mul_add({}, {})",
 +                            Sugg::hir(cx, &args[0], ".."),
 +                            Sugg::hir(cx, &args[0], ".."),
 +                            Sugg::hir(cx, other_addend, ".."),
 +                        ),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
 +    if let ExprKind::Binary(
 +        Spanned {
 +            node: BinOpKind::Add, ..
 +        },
 +        add_lhs,
 +        add_rhs,
 +    ) = args[0].kind
 +    {
 +        // check if expression of the form x * x + y * y
 +        if_chain! {
 +            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind;
 +            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind;
 +            if eq_expr_value(cx, lmul_lhs, lmul_rhs);
 +            if eq_expr_value(cx, rmul_lhs, rmul_rhs);
 +            then {
-                 return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, ".."), Sugg::hir(cx, rargs_0, "..")));
++                return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, "..")));
 +            }
 +        }
 +
 +        // check if expression of the form x.powi(2) + y.powi(2)
 +        if_chain! {
 +            if let ExprKind::MethodCall(
 +                PathSegment { ident: lmethod_name, .. },
 +                _lspan,
 +                [largs_0, largs_1, ..],
 +                _
 +            ) = &add_lhs.kind;
 +            if let ExprKind::MethodCall(
 +                PathSegment { ident: rmethod_name, .. },
 +                _rspan,
 +                [rargs_0, rargs_1, ..],
 +                _
 +            ) = &add_rhs.kind;
 +            if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
 +            if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1);
 +            if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1);
 +            if Int(2) == lvalue && Int(2) == rvalue;
 +            then {
-                     format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")),
++                return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 +    if let Some(message) = detect_hypot(cx, args) {
 +        span_lint_and_sugg(
 +            cx,
 +            IMPRECISE_FLOPS,
 +            expr.span,
 +            "hypotenuse can be computed more accurately",
 +            "consider using",
 +            message,
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +// TODO: Lint expressions of the form `x.exp() - y` where y > 1
 +// and suggest usage of `x.exp_m1() - (y - 1)` instead
 +fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if_chain! {
 +        if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind;
 +        if cx.typeck_results().expr_ty(lhs).is_floating_point();
 +        if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
 +        if F32(1.0) == value || F64(1.0) == value;
 +        if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &lhs.kind;
 +        if cx.typeck_results().expr_ty(self_arg).is_floating_point();
 +        if path.ident.name.as_str() == "exp";
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                IMPRECISE_FLOPS,
 +                expr.span,
 +                "(e.pow(x) - 1) can be computed more accurately",
 +                "consider using",
 +                format!(
 +                    "{}.exp_m1()",
 +                    Sugg::hir(cx, self_arg, "..")
 +                ),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
 +    if_chain! {
 +        if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind;
 +        if cx.typeck_results().expr_ty(lhs).is_floating_point();
 +        if cx.typeck_results().expr_ty(rhs).is_floating_point();
 +        then {
 +            return Some((lhs, rhs));
 +        }
 +    }
 +
 +    None
 +}
 +
 +// TODO: Fix rust-lang/rust-clippy#4735
 +fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if let ExprKind::Binary(
 +        Spanned {
 +            node: BinOpKind::Add, ..
 +        },
 +        lhs,
 +        rhs,
 +    ) = &expr.kind
 +    {
 +        if let Some(parent) = get_parent_expr(cx, expr) {
 +            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind {
 +                if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
 +                    return;
 +                }
 +            }
 +        }
 +
 +        let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
 +            (inner_lhs, inner_rhs, rhs)
 +        } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
 +            (inner_lhs, inner_rhs, lhs)
 +        } else {
 +            return;
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            SUBOPTIMAL_FLOPS,
 +            expr.span,
 +            "multiply and add expressions can be calculated more efficiently and accurately",
 +            "consider using",
 +            format!(
 +                "{}.mul_add({}, {})",
 +                prepare_receiver_sugg(cx, recv),
 +                Sugg::hir(cx, arg1, ".."),
 +                Sugg::hir(cx, arg2, ".."),
 +            ),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +/// Returns true iff expr is an expression which tests whether or not
 +/// test is positive or an expression which tests whether or not test
 +/// is nonnegative.
 +/// Used for check-custom-abs function below
 +fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
 +    if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
 +        match op {
 +            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && eq_expr_value(cx, left, test),
 +            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && eq_expr_value(cx, right, test),
 +            _ => false,
 +        }
 +    } else {
 +        false
 +    }
 +}
 +
 +/// See [`is_testing_positive`]
 +fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
 +    if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
 +        match op {
 +            BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && eq_expr_value(cx, right, test),
 +            BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && eq_expr_value(cx, left, test),
 +            _ => false,
 +        }
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Returns true iff expr is some zero literal
 +fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    match constant_simple(cx, cx.typeck_results(), expr) {
 +        Some(Constant::Int(i)) => i == 0,
 +        Some(Constant::F32(f)) => f == 0.0,
 +        Some(Constant::F64(f)) => f == 0.0,
 +        _ => false,
 +    }
 +}
 +
 +/// If the two expressions are negations of each other, then it returns
 +/// a tuple, in which the first element is true iff expr1 is the
 +/// positive expressions, and the second element is the positive
 +/// one of the two expressions
 +/// If the two expressions are not negations of each other, then it
 +/// returns None.
 +fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> {
 +    if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind {
 +        if eq_expr_value(cx, expr1_negated, expr2) {
 +            return Some((false, expr2));
 +        }
 +    }
 +    if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind {
 +        if eq_expr_value(cx, expr1, expr2_negated) {
 +            return Some((true, expr1));
 +        }
 +    }
 +    None
 +}
 +
 +fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if_chain! {
 +        if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
 +        let if_body_expr = peel_blocks(then);
 +        let else_body_expr = peel_blocks(r#else);
 +        if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
 +        then {
 +            let positive_abs_sugg = (
 +                "manual implementation of `abs` method",
 +                format!("{}.abs()", Sugg::hir(cx, body, "..")),
 +            );
 +            let negative_abs_sugg = (
 +                "manual implementation of negation of `abs` method",
 +                format!("-{}.abs()", Sugg::hir(cx, body, "..")),
 +            );
 +            let sugg = if is_testing_positive(cx, cond, body) {
 +                if if_expr_positive {
 +                    positive_abs_sugg
 +                } else {
 +                    negative_abs_sugg
 +                }
 +            } else if is_testing_negative(cx, cond, body) {
 +                if if_expr_positive {
 +                    negative_abs_sugg
 +                } else {
 +                    positive_abs_sugg
 +                }
 +            } else {
 +                return;
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                SUBOPTIMAL_FLOPS,
 +                expr.span,
 +                sugg.0,
 +                "try",
 +                sugg.1,
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
 +        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
 +        then {
 +            return method_name_a.as_str() == method_name_b.as_str() &&
 +                args_a.len() == args_b.len() &&
 +                (
 +                    ["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
 +                    method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
 +                );
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    // check if expression of the form x.logN() / y.logN()
 +    if_chain! {
 +        if let ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Div, ..
 +            },
 +            lhs,
 +            rhs,
 +        ) = &expr.kind;
 +        if are_same_base_logs(cx, lhs, rhs);
 +        if let ExprKind::MethodCall(_, _, [largs_self, ..], _) = &lhs.kind;
 +        if let ExprKind::MethodCall(_, _, [rargs_self, ..], _) = &rhs.kind;
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                SUBOPTIMAL_FLOPS,
 +                expr.span,
 +                "log base can be expressed more clearly",
 +                "consider using",
 +                format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if_chain! {
 +        if let ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Div, ..
 +            },
 +            div_lhs,
 +            div_rhs,
 +        ) = &expr.kind;
 +        if let ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Mul, ..
 +            },
 +            mul_lhs,
 +            mul_rhs,
 +        ) = &div_lhs.kind;
 +        if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs);
 +        if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs);
 +        then {
 +            // TODO: also check for constant values near PI/180 or 180/PI
 +            if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
 +               (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
 +            {
++                let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
++                if_chain! {
++                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
++                    if let ast::LitKind::Float(ref value, float_type) = literal.node;
++                    if float_type == ast::LitFloatType::Unsuffixed;
++                    then {
++                        if value.as_str().ends_with('.') {
++                            proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
++                        } else {
++                            proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
++                        }
++                    }
++                }
 +                span_lint_and_sugg(
 +                    cx,
 +                    SUBOPTIMAL_FLOPS,
 +                    expr.span,
 +                    "conversion to degrees can be done more accurately",
 +                    "consider using",
-                     format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")),
++                    proposal,
 +                    Applicability::MachineApplicable,
 +                );
 +            } else if
 +                (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
 +                (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
 +            {
++                let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
++                if_chain! {
++                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
++                    if let ast::LitKind::Float(ref value, float_type) = literal.node;
++                    if float_type == ast::LitFloatType::Unsuffixed;
++                    then {
++                        if value.as_str().ends_with('.') {
++                            proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
++                        } else {
++                            proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
++                        }
++                    }
++                }
 +                span_lint_and_sugg(
 +                    cx,
 +                    SUBOPTIMAL_FLOPS,
 +                    expr.span,
 +                    "conversion to radians can be done more accurately",
 +                    "consider using",
++                    proposal,
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // All of these operations are currently not const.
 +        if in_constant(cx, expr.hir_id) {
 +            return;
 +        }
 +
 +        if let ExprKind::MethodCall(path, _, args, _) = &expr.kind {
 +            let recv_ty = cx.typeck_results().expr_ty(&args[0]);
 +
 +            if recv_ty.is_floating_point() {
 +                match path.ident.name.as_str() {
 +                    "ln" => check_ln1p(cx, expr, args),
 +                    "log" => check_log_base(cx, expr, args),
 +                    "powf" => check_powf(cx, expr, args),
 +                    "powi" => check_powi(cx, expr, args),
 +                    "sqrt" => check_hypot(cx, expr, args),
 +                    _ => {},
 +                }
 +            }
 +        } else {
 +            check_expm1(cx, expr);
 +            check_mul_add(cx, expr);
 +            check_custom_abs(cx, expr);
 +            check_log_division(cx, expr);
 +            check_radians(cx, expr);
 +        }
 +    }
 +}
index b4e7bbc767135474d1c33d5b3b601e4548a89ad0,0000000000000000000000000000000000000000..f824f20ca40a017b28d725fcc452fc50f3209e55
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,97 @@@
-     // `1 << 0` is a common pattern in bit manipulation code
-     cmp.node == BinOpKind::Shl
-         && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
-         && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
 +use clippy_utils::source::snippet;
 +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::{clip, unsext};
 +
 +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_lint_pass!(IdentityOp => [IDENTITY_OP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IdentityOp {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::Binary(cmp, left, right) = e.kind {
 +            if is_allowed(cx, cmp, left, right) {
 +                return;
 +            }
 +            match cmp.node {
 +                BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
 +                    check(cx, left, 0, e.span, right.span);
 +                    check(cx, right, 0, e.span, left.span);
 +                },
 +                BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
 +                BinOpKind::Mul => {
 +                    check(cx, left, 1, e.span, right.span);
 +                    check(cx, right, 1, e.span, left.span);
 +                },
 +                BinOpKind::Div => check(cx, right, 1, e.span, left.span),
 +                BinOpKind::BitAnd => {
 +                    check(cx, left, -1, e.span, right.span);
 +                    check(cx, right, -1, e.span, left.span);
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-     if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
-         let check = match *cx.typeck_results().expr_ty(e).kind() {
++    // 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.node == 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(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
++    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_lint(
 +                cx,
 +                IDENTITY_OP,
 +                span,
 +                &format!(
 +                    "the operation is ineffective. Consider reducing it to `{}`",
 +                    snippet(cx, arg, "..")
 +                ),
 +            );
 +        }
 +    }
 +}
index 26a196aab5972ca577430009543fa05fa9d53251,0000000000000000000000000000000000000000..6515975fbffdc8b1b723e4196059168ebdda1256
mode 100644,000000..100644
--- /dev/null
@@@ -1,180 -1,0 +1,180 @@@
-                                 print_lint_and_sugg(cx, &var_name, expr);
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for implicit saturating subtraction.
 +    ///
 +    /// ### Why is this bad?
 +    /// Simplicity and readability. Instead we can easily use an builtin function.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let end: u32 = 10;
 +    /// let start: u32 = 5;
 +    ///
 +    /// let mut i: u32 = end - start;
 +    ///
 +    /// // Bad
 +    /// if i != 0 {
 +    ///     i -= 1;
 +    /// }
 +    ///
 +    /// // Good
 +    /// i = i.saturating_sub(1);
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub IMPLICIT_SATURATING_SUB,
 +    pedantic,
 +    "Perform saturating subtraction instead of implicitly checking lower bound of data type"
 +}
 +
 +declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +        if_chain! {
 +            if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr);
 +
 +            // Check if the conditional expression is a binary operation
 +            if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
 +
 +            // Ensure that the binary operator is >, != and <
 +            if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
 +
 +            // Check if assign operation is done
 +            if let Some(target) = subtracts_one(cx, then);
 +
 +            // Extracting out the variable name
 +            if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
 +
 +            then {
 +                // Handle symmetric conditions in the if statement
 +                let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) {
 +                    if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node {
 +                        (cond_left, cond_right)
 +                    } else {
 +                        return;
 +                    }
 +                } else if SpanlessEq::new(cx).eq_expr(cond_right, target) {
 +                    if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node {
 +                        (cond_right, cond_left)
 +                    } else {
 +                        return;
 +                    }
 +                } else {
 +                    return;
 +                };
 +
 +                // Check if the variable in the condition statement is an integer
 +                if !cx.typeck_results().expr_ty(cond_var).is_integral() {
 +                    return;
 +                }
 +
 +                // Get the variable name
 +                let var_name = ares_path.segments[0].ident.name.as_str();
 +                const INT_TYPES: [LangItem; 5] = [
 +                    LangItem::I8,
 +                    LangItem::I16,
 +                    LangItem::I32,
 +                    LangItem::I64,
 +                    LangItem::Isize
 +                ];
 +
 +                match cond_num_val.kind {
 +                    ExprKind::Lit(ref cond_lit) => {
 +                        // Check if the constant is zero
 +                        if let LitKind::Int(0, _) = cond_lit.node {
 +                            if cx.typeck_results().expr_ty(cond_left).is_signed() {
 +                            } else {
-                                 print_lint_and_sugg(cx, &var_name, expr)
++                                print_lint_and_sugg(cx, var_name, expr);
 +                            };
 +                        }
 +                    },
 +                    ExprKind::Path(QPath::TypeRelative(_, name)) => {
 +                        if_chain! {
 +                            if name.ident.as_str() == "MIN";
 +                            if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id);
 +                            if let Some(impl_id) = cx.tcx.impl_of_method(const_id);
 +                            let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
 +                            if int_ids.any(|int_id| int_id == impl_id);
 +                            then {
-                                 print_lint_and_sugg(cx, &var_name, expr)
++                                print_lint_and_sugg(cx, var_name, expr)
 +                            }
 +                        }
 +                    },
 +                    ExprKind::Call(func, []) => {
 +                        if_chain! {
 +                            if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind;
 +                            if name.ident.as_str() == "min_value";
 +                            if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id);
 +                            if let Some(impl_id) = cx.tcx.impl_of_method(func_id);
 +                            let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
 +                            if int_ids.any(|int_id| int_id == impl_id);
 +                            then {
++                                print_lint_and_sugg(cx, var_name, expr)
 +                            }
 +                        }
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
 +    match peel_blocks_with_stmt(expr).kind {
 +        ExprKind::AssignOp(ref op1, target, value) => {
 +            if_chain! {
 +                if BinOpKind::Sub == op1.node;
 +                // Check if literal being subtracted is one
 +                if let ExprKind::Lit(ref lit1) = value.kind;
 +                if let LitKind::Int(1, _) = lit1.node;
 +                then {
 +                    Some(target)
 +                } else {
 +                    None
 +                }
 +            }
 +        },
 +        ExprKind::Assign(target, value, _) => {
 +            if_chain! {
 +                if let ExprKind::Binary(ref op1, left1, right1) = value.kind;
 +                if BinOpKind::Sub == op1.node;
 +
 +                if SpanlessEq::new(cx).eq_expr(left1, target);
 +
 +                if let ExprKind::Lit(ref lit1) = right1.kind;
 +                if let LitKind::Int(1, _) = lit1.node;
 +                then {
 +                    Some(target)
 +                } else {
 +                    None
 +                }
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) {
 +    span_lint_and_sugg(
 +        cx,
 +        IMPLICIT_SATURATING_SUB,
 +        expr.span,
 +        "implicitly performing saturating subtraction",
 +        "try",
 +        format!("{} = {}.saturating_sub({});", var_name, var_name, '1'),
 +        Applicability::MachineApplicable,
 +    );
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5fe6725b581dc341f4c5e89cfb603c3b64ff528c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,80 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::in_macro;
++use clippy_utils::source::snippet_with_applicability;
++use rustc_errors::Applicability;
++use rustc_hir::{Expr, ExprKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use std::borrow::Cow;
++use std::cmp::Reverse;
++use std::collections::BinaryHeap;
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for tuple structs initialized with field syntax.
++    /// It will however not lint if a base initializer is present.
++    /// The lint will also ignore code in macros.
++    ///
++    /// ### Why is this bad?
++    /// This may be confusing to the uninitiated and adds no
++    /// benefit as opposed to tuple initializers
++    ///
++    /// ### Example
++    /// ```rust
++    /// struct TupleStruct(u8, u16);
++    ///
++    /// let _ = TupleStruct {
++    ///     0: 1,
++    ///     1: 23,
++    /// };
++    ///
++    /// // should be written as
++    /// let base = TupleStruct(1, 23);
++    ///
++    /// // This is OK however
++    /// let _ = TupleStruct { 0: 42, ..base };
++    /// ```
++    #[clippy::version = "1.59.0"]
++    pub INIT_NUMBERED_FIELDS,
++    style,
++    "numbered fields in tuple struct initializer"
++}
++
++declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
++
++impl<'tcx> LateLintPass<'tcx> for NumberedFields {
++    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
++        if let ExprKind::Struct(path, fields, None) = e.kind {
++            if !fields.is_empty()
++                && !in_macro(e.span)
++                && fields
++                    .iter()
++                    .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
++            {
++                let expr_spans = fields
++                    .iter()
++                    .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
++                    .collect::<BinaryHeap<_>>();
++                let mut appl = Applicability::MachineApplicable;
++                let snippet = format!(
++                    "{}({})",
++                    snippet_with_applicability(cx, path.span(), "..", &mut appl),
++                    expr_spans
++                        .into_iter_sorted()
++                        .map(|(_, span)| snippet_with_applicability(cx, span, "..", &mut appl))
++                        .intersperse(Cow::Borrowed(", "))
++                        .collect::<String>()
++                );
++                span_lint_and_sugg(
++                    cx,
++                    INIT_NUMBERED_FIELDS,
++                    e.span,
++                    "used a field initializer for a tuple struct",
++                    "try this instead",
++                    snippet,
++                    appl,
++                );
++            }
++        }
++    }
++}
index 09cd0d22d8b0fb3eb45da2f41aa21f28eb3e85c2,0000000000000000000000000000000000000000..20e6220ec7d3adaa3250873b8285e53e533462a9
mode 100644,000000..100644
--- /dev/null
@@@ -1,493 -1,0 +1,493 @@@
-             return lit == "";
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
 +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,
 +    ItemKind, Mutability, Node, TraitItemRef, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, AssocKind, FnSig, Ty, TyS};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{
 +    source_map::{Span, Spanned, Symbol},
 +    symbol::sym,
 +};
 +
 +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.access_levels.is_exported(item.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.def_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.def_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.access_levels.is_exported(visited_trait.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.def_id.to_def_id(), &mut current_and_super_traits, cx);
 +
 +        let is_empty_method_found = current_and_super_traits
 +            .iter()
 +            .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
 +            .any(|i| {
 +                i.kind == ty::AssocKind::Fn
 +                    && i.fn_has_self_parameter
 +                    && i.ident.name == sym!(is_empty)
 +                    && 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(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 LenOutput<'_> {
 +    fn matches_is_empty_output(self, ty: Ty<'_>) -> 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() && TyS::same_type(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) -> bool`", self_ref),
 +            Self::Option(_) => format!(
 +                "expected signature: `({}self) -> bool` or `({}self) -> Option<bool>",
 +                self_ref, self_ref
 +            ),
 +            Self::Result(..) => format!(
 +                "expected signature: `({}self) -> bool` or `({}self) -> Result<bool>",
 +                self_ref, self_ref
 +            ),
 +        }
 +    }
 +}
 +
 +/// Checks if the given signature matches the expectations for `is_empty`
 +fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> 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(
 +    cx: &LateContext<'_>,
 +    span: Span,
 +    self_kind: ImplicitSelfKind,
 +    output: LenOutput<'_>,
 +    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!(
 +                "{} `{}` has a public `len` method, but no `is_empty` method",
 +                item_kind,
 +                item_name.as_str(),
 +            ),
 +            None,
 +            None,
 +        ),
 +        Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
 +            format!(
 +                "{} `{}` has a public `len` method, but a private `is_empty` method",
 +                item_kind,
 +                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!(
 +                    "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
 +                    item_kind,
 +                    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, _, args, _), &ExprKind::Lit(ref 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, args, &lit.node, op, compare_to);
 +    } else {
 +        check_empty_expr(cx, span, method, lit, op);
 +    }
 +}
 +
 +fn check_len(
 +    cx: &LateContext<'_>,
 +    span: Span,
 +    method_name: Symbol,
 +    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.len() == 1 && has_is_empty(cx, &args[0]) {
 +            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 `{}is_empty` is clearer and more explicit", op),
 +                format!(
 +                    "{}{}.is_empty()",
 +                    op,
 +                    snippet_with_applicability(cx, args[0].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;
 +        span_lint_and_sugg(
 +            cx,
 +            COMPARISON_TO_EMPTY,
 +            span,
 +            "comparison to empty slice",
 +            &format!("using `{}is_empty` is clearer and more explicit", op),
 +            format!(
 +                "{}{}.is_empty()",
 +                op,
 +                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
 +            ),
 +            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 && item.ident.name.as_str() == "is_empty" {
 +            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 {
 +        cx.tcx.inherent_impls(id).iter().any(|imp| {
 +            cx.tcx
 +                .associated_items(*imp)
 +                .in_definition_order()
 +                .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| {
 +            cx.tcx
 +                .associated_items(principal.def_id())
 +                .in_definition_order()
 +                .any(|item| is_is_empty(cx, item))
 +        }),
 +        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
 +        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
 +        ty::Array(..) | ty::Slice(..) | ty::Str => true,
 +        _ => false,
 +    }
 +}
index 3d3999d4cc0d8a99bbc0bd7b408a74834402da8d,0000000000000000000000000000000000000000..944411087e9511dd9dab1e90f3f90a5031b30b11
mode 100644,000000..100644
--- /dev/null
@@@ -1,314 -1,0 +1,315 @@@
 +// 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.
 +
 +store.register_group(true, "clippy::all", Some("clippy_all"), vec![
 +    LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
 +    LintId::of(approx_const::APPROX_CONSTANT),
 +    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
 +    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
 +    LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
 +    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +    LintId::of(attrs::DEPRECATED_CFG_ATTR),
 +    LintId::of(attrs::DEPRECATED_SEMVER),
 +    LintId::of(attrs::MISMATCHED_TARGET_OS),
 +    LintId::of(attrs::USELESS_ATTRIBUTE),
 +    LintId::of(bit_mask::BAD_BIT_MASK),
 +    LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
 +    LintId::of(blacklisted_name::BLACKLISTED_NAME),
 +    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
 +    LintId::of(booleans::LOGIC_BUG),
 +    LintId::of(booleans::NONMINIMAL_BOOL),
 +    LintId::of(casts::CAST_REF_TO_MUT),
 +    LintId::of(casts::CHAR_LIT_AS_U8),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +    LintId::of(casts::UNNECESSARY_CAST),
 +    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
 +    LintId::of(collapsible_if::COLLAPSIBLE_IF),
 +    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
 +    LintId::of(comparison_chain::COMPARISON_CHAIN),
 +    LintId::of(copies::IFS_SAME_COND),
 +    LintId::of(copies::IF_SAME_THEN_ELSE),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(dereference::NEEDLESS_BORROW),
 +    LintId::of(derivable_impls::DERIVABLE_IMPLS),
 +    LintId::of(derive::DERIVE_HASH_XOR_EQ),
 +    LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +    LintId::of(doc::MISSING_SAFETY_DOC),
 +    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
 +    LintId::of(double_comparison::DOUBLE_COMPARISONS),
 +    LintId::of(double_parens::DOUBLE_PARENS),
 +    LintId::of(drop_forget_ref::DROP_COPY),
 +    LintId::of(drop_forget_ref::DROP_REF),
 +    LintId::of(drop_forget_ref::FORGET_COPY),
 +    LintId::of(drop_forget_ref::FORGET_REF),
 +    LintId::of(duration_subsec::DURATION_SUBSEC),
 +    LintId::of(entry::MAP_ENTRY),
 +    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::EQ_OP),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(erasing_op::ERASING_OP),
 +    LintId::of(escape::BOXED_LOCAL),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +    LintId::of(explicit_write::EXPLICIT_WRITE),
 +    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(format::USELESS_FORMAT),
 +    LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
 +    LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
 +    LintId::of(formatting::POSSIBLE_MISSING_COMMA),
 +    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(functions::TOO_MANY_ARGUMENTS),
 +    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
 +    LintId::of(identity_op::IDENTITY_OP),
 +    LintId::of(if_let_mutex::IF_LET_MUTEX),
 +    LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +    LintId::of(infinite_iter::INFINITE_ITER),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
++    LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
 +    LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +    LintId::of(int_plus_one::INT_PLUS_ONE),
 +    LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
 +    LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
 +    LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
 +    LintId::of(lifetimes::NEEDLESS_LIFETIMES),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::EMPTY_LOOP),
 +    LintId::of(loops::EXPLICIT_COUNTER_LOOP),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
 +    LintId::of(loops::ITER_NEXT_LOOP),
 +    LintId::of(loops::MANUAL_FLATTEN),
 +    LintId::of(loops::MANUAL_MEMCPY),
 +    LintId::of(loops::MUT_RANGE_BOUND),
 +    LintId::of(loops::NEEDLESS_COLLECT),
 +    LintId::of(loops::NEEDLESS_RANGE_LOOP),
 +    LintId::of(loops::NEVER_LOOP),
 +    LintId::of(loops::SAME_ITEM_PUSH),
 +    LintId::of(loops::SINGLE_ELEMENT_LOOP),
 +    LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
 +    LintId::of(loops::WHILE_LET_LOOP),
 +    LintId::of(loops::WHILE_LET_ON_ITERATOR),
 +    LintId::of(main_recursion::MAIN_RECURSION),
 +    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
 +    LintId::of(manual_map::MANUAL_MAP),
 +    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +    LintId::of(manual_strip::MANUAL_STRIP),
 +    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
 +    LintId::of(map_clone::MAP_CLONE),
 +    LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
 +    LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
 +    LintId::of(match_result_ok::MATCH_RESULT_OK),
 +    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
 +    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +    LintId::of(matches::MATCH_AS_REF),
 +    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
 +    LintId::of(matches::MATCH_OVERLAPPING_ARM),
 +    LintId::of(matches::MATCH_REF_PATS),
 +    LintId::of(matches::MATCH_SINGLE_BINDING),
 +    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
 +    LintId::of(matches::SINGLE_MATCH),
 +    LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
 +    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
 +    LintId::of(methods::BIND_INSTEAD_OF_MAP),
 +    LintId::of(methods::BYTES_NTH),
 +    LintId::of(methods::CHARS_LAST_CMP),
 +    LintId::of(methods::CHARS_NEXT_CMP),
 +    LintId::of(methods::CLONE_DOUBLE_REF),
 +    LintId::of(methods::CLONE_ON_COPY),
 +    LintId::of(methods::EXPECT_FUN_CALL),
 +    LintId::of(methods::EXTEND_WITH_DRAIN),
 +    LintId::of(methods::FILTER_MAP_IDENTITY),
 +    LintId::of(methods::FILTER_NEXT),
 +    LintId::of(methods::FLAT_MAP_IDENTITY),
 +    LintId::of(methods::INSPECT_FOR_EACH),
 +    LintId::of(methods::INTO_ITER_ON_REF),
 +    LintId::of(methods::ITERATOR_STEP_BY_ZERO),
 +    LintId::of(methods::ITER_CLONED_COLLECT),
 +    LintId::of(methods::ITER_COUNT),
 +    LintId::of(methods::ITER_NEXT_SLICE),
 +    LintId::of(methods::ITER_NTH),
 +    LintId::of(methods::ITER_NTH_ZERO),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_FILTER_MAP),
 +    LintId::of(methods::MANUAL_FIND_MAP),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MANUAL_SPLIT_ONCE),
 +    LintId::of(methods::MANUAL_STR_REPEAT),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::MAP_FLATTEN),
 +    LintId::of(methods::MAP_IDENTITY),
 +    LintId::of(methods::NEEDLESS_SPLITN),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_AS_REF_DEREF),
 +    LintId::of(methods::OPTION_FILTER_MAP),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::OR_FUN_CALL),
 +    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
 +    LintId::of(methods::SEARCH_IS_SOME),
 +    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
 +    LintId::of(methods::SINGLE_CHAR_ADD_STR),
 +    LintId::of(methods::SINGLE_CHAR_PATTERN),
 +    LintId::of(methods::SKIP_WHILE_NEXT),
 +    LintId::of(methods::STRING_EXTEND_CHARS),
 +    LintId::of(methods::SUSPICIOUS_MAP),
 +    LintId::of(methods::SUSPICIOUS_SPLITN),
 +    LintId::of(methods::UNINIT_ASSUMED_INIT),
 +    LintId::of(methods::UNNECESSARY_FILTER_MAP),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNNECESSARY_TO_OWNED),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::USELESS_ASREF),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(methods::ZST_OFFSET),
 +    LintId::of(minmax::MIN_MAX),
 +    LintId::of(misc::CMP_NAN),
 +    LintId::of(misc::CMP_OWNED),
 +    LintId::of(misc::MODULO_ONE),
 +    LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
 +    LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
 +    LintId::of(mut_key::MUTABLE_KEY_TYPE),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(mutex_atomic::MUTEX_ATOMIC),
 +    LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
 +    LintId::of(needless_bool::BOOL_COMPARISON),
 +    LintId::of(needless_bool::NEEDLESS_BOOL),
 +    LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
 +    LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
 +    LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
 +    LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
 +    LintId::of(needless_update::NEEDLESS_UPDATE),
 +    LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(no_effect::NO_EFFECT),
 +    LintId::of(no_effect::UNNECESSARY_OPERATION),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
 +    LintId::of(octal_escapes::OCTAL_ESCAPES),
 +    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
 +    LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
 +    LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
 +    LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +    LintId::of(precedence::PRECEDENCE),
 +    LintId::of(ptr::CMP_NULL),
 +    LintId::of(ptr::INVALID_NULL_PTR_USAGE),
 +    LintId::of(ptr::MUT_FROM_REF),
 +    LintId::of(ptr::PTR_ARG),
 +    LintId::of(ptr_eq::PTR_EQ),
 +    LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +    LintId::of(question_mark::QUESTION_MARK),
 +    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
 +    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
 +    LintId::of(ranges::REVERSED_EMPTY_RANGES),
 +    LintId::of(redundant_clone::REDUNDANT_CLONE),
 +    LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
 +    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
 +    LintId::of(redundant_slicing::REDUNDANT_SLICING),
 +    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +    LintId::of(reference::DEREF_ADDROF),
 +    LintId::of(reference::REF_IN_DEREF),
 +    LintId::of(regex::INVALID_REGEX),
 +    LintId::of(repeat_once::REPEAT_ONCE),
 +    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
 +    LintId::of(returns::LET_AND_RETURN),
 +    LintId::of(returns::NEEDLESS_RETURN),
 +    LintId::of(self_assignment::SELF_ASSIGNMENT),
 +    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
 +    LintId::of(serde_api::SERDE_API_MISUSE),
 +    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +    LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
 +    LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
 +    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
 +    LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
 +    LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +    LintId::of(swap::ALMOST_SWAPPED),
 +    LintId::of(swap::MANUAL_SWAP),
 +    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +    LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
 +    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
 +    LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
 +    LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
 +    LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
 +    LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
 +    LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
 +    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
 +    LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
 +    LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +    LintId::of(transmute::WRONG_TRANSMUTE),
 +    LintId::of(transmuting_null::TRANSMUTING_NULL),
 +    LintId::of(try_err::TRY_ERR),
 +    LintId::of(types::BORROWED_BOX),
 +    LintId::of(types::BOX_COLLECTION),
 +    LintId::of(types::REDUNDANT_ALLOCATION),
 +    LintId::of(types::TYPE_COMPLEXITY),
 +    LintId::of(types::VEC_BOX),
 +    LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(unicode::INVISIBLE_CHARACTERS),
 +    LintId::of(uninit_vec::UNINIT_VEC),
 +    LintId::of(unit_hash::UNIT_HASH),
 +    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +    LintId::of(unit_types::UNIT_ARG),
 +    LintId::of(unit_types::UNIT_CMP),
 +    LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
 +    LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +    LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
 +    LintId::of(unused_unit::UNUSED_UNIT),
 +    LintId::of(unwrap::PANICKING_UNWRAP),
 +    LintId::of(unwrap::UNNECESSARY_UNWRAP),
 +    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +    LintId::of(useless_conversion::USELESS_CONVERSION),
 +    LintId::of(vec::USELESS_VEC),
 +    LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
 +    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +    LintId::of(write::PRINTLN_EMPTY_STRING),
 +    LintId::of(write::PRINT_LITERAL),
 +    LintId::of(write::PRINT_WITH_NEWLINE),
 +    LintId::of(write::WRITELN_EMPTY_STRING),
 +    LintId::of(write::WRITE_LITERAL),
 +    LintId::of(write::WRITE_WITH_NEWLINE),
 +    LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +])
index 766c5ba1bcb0f73e3837ad856f266257b433ebea,0000000000000000000000000000000000000000..002122793f3b6b4c2a26965be3bbbd1239f2d1cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,531 -1,0 +1,532 @@@
 +// 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.
 +
 +store.register_lints(&[
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::CLIPPY_LINTS_INTERNAL,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::COMPILER_LINT_FUNCTIONS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::DEFAULT_LINT,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::IF_CHAIN_STYLE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::INTERNING_DEFINED_SYMBOL,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::INVALID_PATHS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::LINT_WITHOUT_LINT_PASS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::OUTER_EXPN_EXPN_DATA,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::PRODUCE_ICE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::UNNECESSARY_SYMBOL_STR,
 +    absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
 +    approx_const::APPROX_CONSTANT,
 +    arithmetic::FLOAT_ARITHMETIC,
 +    arithmetic::INTEGER_ARITHMETIC,
 +    as_conversions::AS_CONVERSIONS,
 +    asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
 +    asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
 +    assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
 +    assign_ops::ASSIGN_OP_PATTERN,
 +    assign_ops::MISREFACTORED_ASSIGN_OP,
 +    async_yields_async::ASYNC_YIELDS_ASYNC,
 +    attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
 +    attrs::DEPRECATED_CFG_ATTR,
 +    attrs::DEPRECATED_SEMVER,
 +    attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
 +    attrs::INLINE_ALWAYS,
 +    attrs::MISMATCHED_TARGET_OS,
 +    attrs::USELESS_ATTRIBUTE,
 +    await_holding_invalid::AWAIT_HOLDING_LOCK,
 +    await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
 +    bit_mask::BAD_BIT_MASK,
 +    bit_mask::INEFFECTIVE_BIT_MASK,
 +    bit_mask::VERBOSE_BIT_MASK,
 +    blacklisted_name::BLACKLISTED_NAME,
 +    blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
 +    bool_assert_comparison::BOOL_ASSERT_COMPARISON,
 +    booleans::LOGIC_BUG,
 +    booleans::NONMINIMAL_BOOL,
 +    bytecount::NAIVE_BYTECOUNT,
 +    cargo_common_metadata::CARGO_COMMON_METADATA,
 +    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
 +    casts::CAST_LOSSLESS,
 +    casts::CAST_POSSIBLE_TRUNCATION,
 +    casts::CAST_POSSIBLE_WRAP,
 +    casts::CAST_PRECISION_LOSS,
 +    casts::CAST_PTR_ALIGNMENT,
 +    casts::CAST_REF_TO_MUT,
 +    casts::CAST_SIGN_LOSS,
 +    casts::CHAR_LIT_AS_U8,
 +    casts::FN_TO_NUMERIC_CAST,
 +    casts::FN_TO_NUMERIC_CAST_ANY,
 +    casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    casts::PTR_AS_PTR,
 +    casts::UNNECESSARY_CAST,
 +    checked_conversions::CHECKED_CONVERSIONS,
 +    cognitive_complexity::COGNITIVE_COMPLEXITY,
 +    collapsible_if::COLLAPSIBLE_ELSE_IF,
 +    collapsible_if::COLLAPSIBLE_IF,
 +    collapsible_match::COLLAPSIBLE_MATCH,
 +    comparison_chain::COMPARISON_CHAIN,
 +    copies::BRANCHES_SHARING_CODE,
 +    copies::IFS_SAME_COND,
 +    copies::IF_SAME_THEN_ELSE,
 +    copies::SAME_FUNCTIONS_IN_IF_CONDITION,
 +    copy_iterator::COPY_ITERATOR,
 +    create_dir::CREATE_DIR,
 +    dbg_macro::DBG_MACRO,
 +    default::DEFAULT_TRAIT_ACCESS,
 +    default::FIELD_REASSIGN_WITH_DEFAULT,
 +    default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
 +    dereference::EXPLICIT_DEREF_METHODS,
 +    dereference::NEEDLESS_BORROW,
 +    dereference::REF_BINDING_TO_REFERENCE,
 +    derivable_impls::DERIVABLE_IMPLS,
 +    derive::DERIVE_HASH_XOR_EQ,
 +    derive::DERIVE_ORD_XOR_PARTIAL_ORD,
 +    derive::EXPL_IMPL_CLONE_ON_COPY,
 +    derive::UNSAFE_DERIVE_DESERIALIZE,
 +    disallowed_methods::DISALLOWED_METHODS,
 +    disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
 +    disallowed_types::DISALLOWED_TYPES,
 +    doc::DOC_MARKDOWN,
 +    doc::MISSING_ERRORS_DOC,
 +    doc::MISSING_PANICS_DOC,
 +    doc::MISSING_SAFETY_DOC,
 +    doc::NEEDLESS_DOCTEST_MAIN,
 +    double_comparison::DOUBLE_COMPARISONS,
 +    double_parens::DOUBLE_PARENS,
 +    drop_forget_ref::DROP_COPY,
 +    drop_forget_ref::DROP_REF,
 +    drop_forget_ref::FORGET_COPY,
 +    drop_forget_ref::FORGET_REF,
 +    duration_subsec::DURATION_SUBSEC,
 +    else_if_without_else::ELSE_IF_WITHOUT_ELSE,
 +    empty_enum::EMPTY_ENUM,
 +    entry::MAP_ENTRY,
 +    enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
 +    enum_variants::ENUM_VARIANT_NAMES,
 +    enum_variants::MODULE_INCEPTION,
 +    enum_variants::MODULE_NAME_REPETITIONS,
 +    eq_op::EQ_OP,
 +    eq_op::OP_REF,
 +    equatable_if_let::EQUATABLE_IF_LET,
 +    erasing_op::ERASING_OP,
 +    escape::BOXED_LOCAL,
 +    eta_reduction::REDUNDANT_CLOSURE,
 +    eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
 +    eval_order_dependence::DIVERGING_SUB_EXPRESSION,
 +    eval_order_dependence::EVAL_ORDER_DEPENDENCE,
 +    excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
 +    excessive_bools::STRUCT_EXCESSIVE_BOOLS,
 +    exhaustive_items::EXHAUSTIVE_ENUMS,
 +    exhaustive_items::EXHAUSTIVE_STRUCTS,
 +    exit::EXIT,
 +    explicit_write::EXPLICIT_WRITE,
 +    fallible_impl_from::FALLIBLE_IMPL_FROM,
 +    feature_name::NEGATIVE_FEATURE_NAMES,
 +    feature_name::REDUNDANT_FEATURE_NAMES,
 +    float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
 +    float_literal::EXCESSIVE_PRECISION,
 +    float_literal::LOSSY_FLOAT_LITERAL,
 +    floating_point_arithmetic::IMPRECISE_FLOPS,
 +    floating_point_arithmetic::SUBOPTIMAL_FLOPS,
 +    format::USELESS_FORMAT,
 +    format_args::FORMAT_IN_FORMAT_ARGS,
 +    format_args::TO_STRING_IN_FORMAT_ARGS,
 +    formatting::POSSIBLE_MISSING_COMMA,
 +    formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
 +    formatting::SUSPICIOUS_ELSE_FORMATTING,
 +    formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
 +    from_over_into::FROM_OVER_INTO,
 +    from_str_radix_10::FROM_STR_RADIX_10,
 +    functions::DOUBLE_MUST_USE,
 +    functions::MUST_USE_CANDIDATE,
 +    functions::MUST_USE_UNIT,
 +    functions::NOT_UNSAFE_PTR_ARG_DEREF,
 +    functions::RESULT_UNIT_ERR,
 +    functions::TOO_MANY_ARGUMENTS,
 +    functions::TOO_MANY_LINES,
 +    future_not_send::FUTURE_NOT_SEND,
 +    get_last_with_len::GET_LAST_WITH_LEN,
 +    identity_op::IDENTITY_OP,
 +    if_let_mutex::IF_LET_MUTEX,
 +    if_not_else::IF_NOT_ELSE,
 +    if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
 +    implicit_hasher::IMPLICIT_HASHER,
 +    implicit_return::IMPLICIT_RETURN,
 +    implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
 +    inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
 +    index_refutable_slice::INDEX_REFUTABLE_SLICE,
 +    indexing_slicing::INDEXING_SLICING,
 +    indexing_slicing::OUT_OF_BOUNDS_INDEXING,
 +    infinite_iter::INFINITE_ITER,
 +    infinite_iter::MAYBE_INFINITE_ITER,
 +    inherent_impl::MULTIPLE_INHERENT_IMPL,
 +    inherent_to_string::INHERENT_TO_STRING,
 +    inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
++    init_numbered_fields::INIT_NUMBERED_FIELDS,
 +    inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
 +    int_plus_one::INT_PLUS_ONE,
 +    integer_division::INTEGER_DIVISION,
 +    invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
 +    items_after_statements::ITEMS_AFTER_STATEMENTS,
 +    iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
 +    large_const_arrays::LARGE_CONST_ARRAYS,
 +    large_enum_variant::LARGE_ENUM_VARIANT,
 +    large_stack_arrays::LARGE_STACK_ARRAYS,
 +    len_zero::COMPARISON_TO_EMPTY,
 +    len_zero::LEN_WITHOUT_IS_EMPTY,
 +    len_zero::LEN_ZERO,
 +    let_if_seq::USELESS_LET_IF_SEQ,
 +    let_underscore::LET_UNDERSCORE_DROP,
 +    let_underscore::LET_UNDERSCORE_LOCK,
 +    let_underscore::LET_UNDERSCORE_MUST_USE,
 +    lifetimes::EXTRA_UNUSED_LIFETIMES,
 +    lifetimes::NEEDLESS_LIFETIMES,
 +    literal_representation::DECIMAL_LITERAL_REPRESENTATION,
 +    literal_representation::INCONSISTENT_DIGIT_GROUPING,
 +    literal_representation::LARGE_DIGIT_GROUPS,
 +    literal_representation::MISTYPED_LITERAL_SUFFIXES,
 +    literal_representation::UNREADABLE_LITERAL,
 +    literal_representation::UNUSUAL_BYTE_GROUPINGS,
 +    loops::EMPTY_LOOP,
 +    loops::EXPLICIT_COUNTER_LOOP,
 +    loops::EXPLICIT_INTO_ITER_LOOP,
 +    loops::EXPLICIT_ITER_LOOP,
 +    loops::FOR_KV_MAP,
 +    loops::FOR_LOOPS_OVER_FALLIBLES,
 +    loops::ITER_NEXT_LOOP,
 +    loops::MANUAL_FLATTEN,
 +    loops::MANUAL_MEMCPY,
 +    loops::MUT_RANGE_BOUND,
 +    loops::NEEDLESS_COLLECT,
 +    loops::NEEDLESS_RANGE_LOOP,
 +    loops::NEVER_LOOP,
 +    loops::SAME_ITEM_PUSH,
 +    loops::SINGLE_ELEMENT_LOOP,
 +    loops::WHILE_IMMUTABLE_CONDITION,
 +    loops::WHILE_LET_LOOP,
 +    loops::WHILE_LET_ON_ITERATOR,
 +    macro_use::MACRO_USE_IMPORTS,
 +    main_recursion::MAIN_RECURSION,
 +    manual_assert::MANUAL_ASSERT,
 +    manual_async_fn::MANUAL_ASYNC_FN,
 +    manual_map::MANUAL_MAP,
 +    manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
 +    manual_ok_or::MANUAL_OK_OR,
 +    manual_strip::MANUAL_STRIP,
 +    manual_unwrap_or::MANUAL_UNWRAP_OR,
 +    map_clone::MAP_CLONE,
 +    map_err_ignore::MAP_ERR_IGNORE,
 +    map_unit_fn::OPTION_MAP_UNIT_FN,
 +    map_unit_fn::RESULT_MAP_UNIT_FN,
 +    match_on_vec_items::MATCH_ON_VEC_ITEMS,
 +    match_result_ok::MATCH_RESULT_OK,
 +    match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
 +    matches::INFALLIBLE_DESTRUCTURING_MATCH,
 +    matches::MATCH_AS_REF,
 +    matches::MATCH_BOOL,
 +    matches::MATCH_LIKE_MATCHES_MACRO,
 +    matches::MATCH_OVERLAPPING_ARM,
 +    matches::MATCH_REF_PATS,
 +    matches::MATCH_SAME_ARMS,
 +    matches::MATCH_SINGLE_BINDING,
 +    matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    matches::MATCH_WILD_ERR_ARM,
 +    matches::REDUNDANT_PATTERN_MATCHING,
 +    matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    matches::SINGLE_MATCH,
 +    matches::SINGLE_MATCH_ELSE,
 +    matches::WILDCARD_ENUM_MATCH_ARM,
 +    matches::WILDCARD_IN_OR_PATTERNS,
 +    mem_forget::MEM_FORGET,
 +    mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
 +    mem_replace::MEM_REPLACE_WITH_DEFAULT,
 +    mem_replace::MEM_REPLACE_WITH_UNINIT,
 +    methods::BIND_INSTEAD_OF_MAP,
 +    methods::BYTES_NTH,
 +    methods::CHARS_LAST_CMP,
 +    methods::CHARS_NEXT_CMP,
 +    methods::CLONED_INSTEAD_OF_COPIED,
 +    methods::CLONE_DOUBLE_REF,
 +    methods::CLONE_ON_COPY,
 +    methods::CLONE_ON_REF_PTR,
 +    methods::EXPECT_FUN_CALL,
 +    methods::EXPECT_USED,
 +    methods::EXTEND_WITH_DRAIN,
 +    methods::FILETYPE_IS_FILE,
 +    methods::FILTER_MAP_IDENTITY,
 +    methods::FILTER_MAP_NEXT,
 +    methods::FILTER_NEXT,
 +    methods::FLAT_MAP_IDENTITY,
 +    methods::FLAT_MAP_OPTION,
 +    methods::FROM_ITER_INSTEAD_OF_COLLECT,
 +    methods::GET_UNWRAP,
 +    methods::IMPLICIT_CLONE,
 +    methods::INEFFICIENT_TO_STRING,
 +    methods::INSPECT_FOR_EACH,
 +    methods::INTO_ITER_ON_REF,
 +    methods::ITERATOR_STEP_BY_ZERO,
 +    methods::ITER_CLONED_COLLECT,
 +    methods::ITER_COUNT,
 +    methods::ITER_NEXT_SLICE,
 +    methods::ITER_NTH,
 +    methods::ITER_NTH_ZERO,
 +    methods::ITER_SKIP_NEXT,
 +    methods::MANUAL_FILTER_MAP,
 +    methods::MANUAL_FIND_MAP,
 +    methods::MANUAL_SATURATING_ARITHMETIC,
 +    methods::MANUAL_SPLIT_ONCE,
 +    methods::MANUAL_STR_REPEAT,
 +    methods::MAP_COLLECT_RESULT_UNIT,
 +    methods::MAP_FLATTEN,
 +    methods::MAP_IDENTITY,
 +    methods::MAP_UNWRAP_OR,
 +    methods::NEEDLESS_SPLITN,
 +    methods::NEW_RET_NO_SELF,
 +    methods::OK_EXPECT,
 +    methods::OPTION_AS_REF_DEREF,
 +    methods::OPTION_FILTER_MAP,
 +    methods::OPTION_MAP_OR_NONE,
 +    methods::OR_FUN_CALL,
 +    methods::RESULT_MAP_OR_INTO_OPTION,
 +    methods::SEARCH_IS_SOME,
 +    methods::SHOULD_IMPLEMENT_TRAIT,
 +    methods::SINGLE_CHAR_ADD_STR,
 +    methods::SINGLE_CHAR_PATTERN,
 +    methods::SKIP_WHILE_NEXT,
 +    methods::STRING_EXTEND_CHARS,
 +    methods::SUSPICIOUS_MAP,
 +    methods::SUSPICIOUS_SPLITN,
 +    methods::UNINIT_ASSUMED_INIT,
 +    methods::UNNECESSARY_FILTER_MAP,
 +    methods::UNNECESSARY_FOLD,
 +    methods::UNNECESSARY_LAZY_EVALUATIONS,
 +    methods::UNNECESSARY_TO_OWNED,
 +    methods::UNWRAP_OR_ELSE_DEFAULT,
 +    methods::UNWRAP_USED,
 +    methods::USELESS_ASREF,
 +    methods::WRONG_SELF_CONVENTION,
 +    methods::ZST_OFFSET,
 +    minmax::MIN_MAX,
 +    misc::CMP_NAN,
 +    misc::CMP_OWNED,
 +    misc::FLOAT_CMP,
 +    misc::FLOAT_CMP_CONST,
 +    misc::MODULO_ONE,
 +    misc::SHORT_CIRCUIT_STATEMENT,
 +    misc::TOPLEVEL_REF_ARG,
 +    misc::USED_UNDERSCORE_BINDING,
 +    misc::ZERO_PTR,
 +    misc_early::BUILTIN_TYPE_SHADOW,
 +    misc_early::DOUBLE_NEG,
 +    misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
 +    misc_early::MIXED_CASE_HEX_LITERALS,
 +    misc_early::REDUNDANT_PATTERN,
 +    misc_early::SEPARATED_LITERAL_SUFFIX,
 +    misc_early::UNNEEDED_FIELD_PATTERN,
 +    misc_early::UNNEEDED_WILDCARD_PATTERN,
 +    misc_early::UNSEPARATED_LITERAL_SUFFIX,
 +    misc_early::ZERO_PREFIXED_LITERAL,
 +    missing_const_for_fn::MISSING_CONST_FOR_FN,
 +    missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
 +    missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
 +    missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
 +    module_style::MOD_MODULE_FILES,
 +    module_style::SELF_NAMED_MODULE_FILES,
 +    modulo_arithmetic::MODULO_ARITHMETIC,
 +    multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
 +    mut_key::MUTABLE_KEY_TYPE,
 +    mut_mut::MUT_MUT,
 +    mut_mutex_lock::MUT_MUTEX_LOCK,
 +    mut_reference::UNNECESSARY_MUT_PASSED,
 +    mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
 +    mutex_atomic::MUTEX_ATOMIC,
 +    mutex_atomic::MUTEX_INTEGER,
 +    needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
 +    needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
 +    needless_bool::BOOL_COMPARISON,
 +    needless_bool::NEEDLESS_BOOL,
 +    needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
 +    needless_continue::NEEDLESS_CONTINUE,
 +    needless_for_each::NEEDLESS_FOR_EACH,
 +    needless_late_init::NEEDLESS_LATE_INIT,
 +    needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
 +    needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
 +    needless_question_mark::NEEDLESS_QUESTION_MARK,
 +    needless_update::NEEDLESS_UPDATE,
 +    neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
 +    neg_multiply::NEG_MULTIPLY,
 +    new_without_default::NEW_WITHOUT_DEFAULT,
 +    no_effect::NO_EFFECT,
 +    no_effect::NO_EFFECT_UNDERSCORE_BINDING,
 +    no_effect::UNNECESSARY_OPERATION,
 +    non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
 +    non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
 +    non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
 +    non_expressive_names::MANY_SINGLE_CHAR_NAMES,
 +    non_expressive_names::SIMILAR_NAMES,
 +    non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
 +    non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
 +    nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
 +    octal_escapes::OCTAL_ESCAPES,
 +    open_options::NONSENSICAL_OPEN_OPTIONS,
 +    option_env_unwrap::OPTION_ENV_UNWRAP,
 +    option_if_let_else::OPTION_IF_LET_ELSE,
 +    overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
 +    panic_in_result_fn::PANIC_IN_RESULT_FN,
 +    panic_unimplemented::PANIC,
 +    panic_unimplemented::TODO,
 +    panic_unimplemented::UNIMPLEMENTED,
 +    panic_unimplemented::UNREACHABLE,
 +    partialeq_ne_impl::PARTIALEQ_NE_IMPL,
 +    pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
 +    pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
 +    path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
 +    pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
 +    precedence::PRECEDENCE,
 +    ptr::CMP_NULL,
 +    ptr::INVALID_NULL_PTR_USAGE,
 +    ptr::MUT_FROM_REF,
 +    ptr::PTR_ARG,
 +    ptr_eq::PTR_EQ,
 +    ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
 +    question_mark::QUESTION_MARK,
 +    ranges::MANUAL_RANGE_CONTAINS,
 +    ranges::RANGE_MINUS_ONE,
 +    ranges::RANGE_PLUS_ONE,
 +    ranges::RANGE_ZIP_WITH_LEN,
 +    ranges::REVERSED_EMPTY_RANGES,
 +    redundant_clone::REDUNDANT_CLONE,
 +    redundant_closure_call::REDUNDANT_CLOSURE_CALL,
 +    redundant_else::REDUNDANT_ELSE,
 +    redundant_field_names::REDUNDANT_FIELD_NAMES,
 +    redundant_pub_crate::REDUNDANT_PUB_CRATE,
 +    redundant_slicing::REDUNDANT_SLICING,
 +    redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
 +    ref_option_ref::REF_OPTION_REF,
 +    reference::DEREF_ADDROF,
 +    reference::REF_IN_DEREF,
 +    regex::INVALID_REGEX,
 +    regex::TRIVIAL_REGEX,
 +    repeat_once::REPEAT_ONCE,
 +    return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
 +    returns::LET_AND_RETURN,
 +    returns::NEEDLESS_RETURN,
 +    same_name_method::SAME_NAME_METHOD,
 +    self_assignment::SELF_ASSIGNMENT,
 +    self_named_constructors::SELF_NAMED_CONSTRUCTORS,
 +    semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
 +    serde_api::SERDE_API_MISUSE,
 +    shadow::SHADOW_REUSE,
 +    shadow::SHADOW_SAME,
 +    shadow::SHADOW_UNRELATED,
 +    single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
 +    size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
 +    slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
 +    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
 +    strings::STRING_ADD,
 +    strings::STRING_ADD_ASSIGN,
 +    strings::STRING_FROM_UTF8_AS_BYTES,
 +    strings::STRING_LIT_AS_BYTES,
 +    strings::STRING_SLICE,
 +    strings::STRING_TO_STRING,
 +    strings::STR_TO_STRING,
 +    strlen_on_c_strings::STRLEN_ON_C_STRINGS,
 +    suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
 +    suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
 +    suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
 +    swap::ALMOST_SWAPPED,
 +    swap::MANUAL_SWAP,
 +    tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
 +    temporary_assignment::TEMPORARY_ASSIGNMENT,
 +    to_digit_is_some::TO_DIGIT_IS_SOME,
 +    to_string_in_display::TO_STRING_IN_DISPLAY,
 +    trailing_empty_array::TRAILING_EMPTY_ARRAY,
 +    trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
 +    trait_bounds::TYPE_REPETITION_IN_BOUNDS,
 +    transmute::CROSSPOINTER_TRANSMUTE,
 +    transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    transmute::TRANSMUTE_BYTES_TO_STR,
 +    transmute::TRANSMUTE_FLOAT_TO_INT,
 +    transmute::TRANSMUTE_INT_TO_BOOL,
 +    transmute::TRANSMUTE_INT_TO_CHAR,
 +    transmute::TRANSMUTE_INT_TO_FLOAT,
 +    transmute::TRANSMUTE_NUM_TO_BYTES,
 +    transmute::TRANSMUTE_PTR_TO_PTR,
 +    transmute::TRANSMUTE_PTR_TO_REF,
 +    transmute::UNSOUND_COLLECTION_TRANSMUTE,
 +    transmute::USELESS_TRANSMUTE,
 +    transmute::WRONG_TRANSMUTE,
 +    transmuting_null::TRANSMUTING_NULL,
 +    try_err::TRY_ERR,
 +    types::BORROWED_BOX,
 +    types::BOX_COLLECTION,
 +    types::LINKEDLIST,
 +    types::OPTION_OPTION,
 +    types::RC_BUFFER,
 +    types::RC_MUTEX,
 +    types::REDUNDANT_ALLOCATION,
 +    types::TYPE_COMPLEXITY,
 +    types::VEC_BOX,
 +    undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
 +    undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
 +    unicode::INVISIBLE_CHARACTERS,
 +    unicode::NON_ASCII_LITERAL,
 +    unicode::UNICODE_NOT_NFC,
 +    uninit_vec::UNINIT_VEC,
 +    unit_hash::UNIT_HASH,
 +    unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
 +    unit_types::LET_UNIT_VALUE,
 +    unit_types::UNIT_ARG,
 +    unit_types::UNIT_CMP,
 +    unnamed_address::FN_ADDRESS_COMPARISONS,
 +    unnamed_address::VTABLE_ADDRESS_COMPARISONS,
 +    unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
 +    unnecessary_sort_by::UNNECESSARY_SORT_BY,
 +    unnecessary_wraps::UNNECESSARY_WRAPS,
 +    unnested_or_patterns::UNNESTED_OR_PATTERNS,
 +    unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
 +    unused_async::UNUSED_ASYNC,
 +    unused_io_amount::UNUSED_IO_AMOUNT,
 +    unused_self::UNUSED_SELF,
 +    unused_unit::UNUSED_UNIT,
 +    unwrap::PANICKING_UNWRAP,
 +    unwrap::UNNECESSARY_UNWRAP,
 +    unwrap_in_result::UNWRAP_IN_RESULT,
 +    upper_case_acronyms::UPPER_CASE_ACRONYMS,
 +    use_self::USE_SELF,
 +    useless_conversion::USELESS_CONVERSION,
 +    vec::USELESS_VEC,
 +    vec_init_then_push::VEC_INIT_THEN_PUSH,
 +    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
 +    verbose_file_reads::VERBOSE_FILE_READS,
 +    wildcard_dependencies::WILDCARD_DEPENDENCIES,
 +    wildcard_imports::ENUM_GLOB_USE,
 +    wildcard_imports::WILDCARD_IMPORTS,
 +    write::PRINTLN_EMPTY_STRING,
 +    write::PRINT_LITERAL,
 +    write::PRINT_STDERR,
 +    write::PRINT_STDOUT,
 +    write::PRINT_WITH_NEWLINE,
 +    write::USE_DEBUG,
 +    write::WRITELN_EMPTY_STRING,
 +    write::WRITE_LITERAL,
 +    write::WRITE_WITH_NEWLINE,
 +    zero_div_zero::ZERO_DIVIDED_BY_ZERO,
 +    zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
 +])
index ea87e7e7a73687bb37b9385396c6c4ebc5c2b3a2,0000000000000000000000000000000000000000..1a0b869d40adb5f2fb8e4c9ef89ea812533f0569
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,115 @@@
 +// 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.
 +
 +store.register_group(true, "clippy::style", Some("clippy_style"), vec![
 +    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
 +    LintId::of(blacklisted_name::BLACKLISTED_NAME),
 +    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
 +    LintId::of(collapsible_if::COLLAPSIBLE_IF),
 +    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
 +    LintId::of(comparison_chain::COMPARISON_CHAIN),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(dereference::NEEDLESS_BORROW),
 +    LintId::of(doc::MISSING_SAFETY_DOC),
 +    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
++    LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::NEEDLESS_RANGE_LOOP),
 +    LintId::of(loops::SAME_ITEM_PUSH),
 +    LintId::of(loops::WHILE_LET_ON_ITERATOR),
 +    LintId::of(main_recursion::MAIN_RECURSION),
 +    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
 +    LintId::of(manual_map::MANUAL_MAP),
 +    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +    LintId::of(map_clone::MAP_CLONE),
 +    LintId::of(match_result_ok::MATCH_RESULT_OK),
 +    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
 +    LintId::of(matches::MATCH_OVERLAPPING_ARM),
 +    LintId::of(matches::MATCH_REF_PATS),
 +    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
 +    LintId::of(matches::SINGLE_MATCH),
 +    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +    LintId::of(methods::BYTES_NTH),
 +    LintId::of(methods::CHARS_LAST_CMP),
 +    LintId::of(methods::CHARS_NEXT_CMP),
 +    LintId::of(methods::INTO_ITER_ON_REF),
 +    LintId::of(methods::ITER_CLONED_COLLECT),
 +    LintId::of(methods::ITER_NEXT_SLICE),
 +    LintId::of(methods::ITER_NTH_ZERO),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
 +    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
 +    LintId::of(methods::SINGLE_CHAR_ADD_STR),
 +    LintId::of(methods::STRING_EXTEND_CHARS),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(ptr::CMP_NULL),
 +    LintId::of(ptr::PTR_ARG),
 +    LintId::of(ptr_eq::PTR_EQ),
 +    LintId::of(question_mark::QUESTION_MARK),
 +    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
 +    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
 +    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +    LintId::of(returns::LET_AND_RETURN),
 +    LintId::of(returns::NEEDLESS_RETURN),
 +    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
 +    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
 +    LintId::of(try_err::TRY_ERR),
 +    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +    LintId::of(unused_unit::UNUSED_UNIT),
 +    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +    LintId::of(write::PRINTLN_EMPTY_STRING),
 +    LintId::of(write::PRINT_LITERAL),
 +    LintId::of(write::PRINT_WITH_NEWLINE),
 +    LintId::of(write::WRITELN_EMPTY_STRING),
 +    LintId::of(write::WRITE_LITERAL),
 +    LintId::of(write::WRITE_WITH_NEWLINE),
 +])
index d1c7956a7a5c89f8ce9be63a2c6d5f6b21e52979,0000000000000000000000000000000000000000..d4687a1e2879749d7253fcf0d2bc90ece839f7ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,950 -1,0 +1,954 @@@
- #![feature(control_flow_enum)]
- #![feature(let_else)]
 +// error-pattern:cargo-clippy
 +
++#![feature(binary_heap_into_iter_sorted)]
 +#![feature(box_patterns)]
++#![feature(control_flow_enum)]
 +#![feature(drain_filter)]
 +#![feature(in_band_lifetimes)]
++#![feature(iter_intersperse)]
++#![feature(let_else)]
 +#![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)]
 +
 +// 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_data_structures;
 +extern crate rustc_driver;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_pretty;
 +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;
 +extern crate rustc_parse_format;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +extern crate clippy_utils;
 +
 +use clippy_utils::parse_msrv;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_lint::LintId;
 +use rustc_session::Session;
 +
 +/// Macro used to declare a Clippy lint.
 +///
 +/// Every lint declaration consists of 4 parts:
 +///
 +/// 1. The documentation, which is used for the website
 +/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
 +/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
 +///    `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
 +/// 4. The `description` that contains a short explanation on what's wrong with code where the
 +///    lint is triggered.
 +///
 +/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
 +/// enabled by default. As said in the README.md of this repository, if the lint level mapping
 +/// changes, please update README.md.
 +///
 +/// # Example
 +///
 +/// ```
 +/// #![feature(rustc_private)]
 +/// extern crate rustc_session;
 +/// use rustc_session::declare_tool_lint;
 +/// use clippy_lints::declare_clippy_lint;
 +///
 +/// declare_clippy_lint! {
 +///     /// ### What it does
 +///     /// Checks for ... (describe what the lint matches).
 +///     ///
 +///     /// ### Why is this bad?
 +///     /// Supply the reason for linting the code.
 +///     ///
 +///     /// ### Example
 +///     /// ```rust
 +///     /// // Bad
 +///     /// Insert a short example of code that triggers the lint
 +///     ///
 +///     /// // Good
 +///     /// Insert a short example of improved code that doesn't trigger the lint
 +///     /// ```
 +///     pub LINT_NAME,
 +///     pedantic,
 +///     "description"
 +/// }
 +/// ```
 +/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +#[macro_export]
 +macro_rules! declare_clippy_lint {
 +    { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +}
 +
 +#[cfg(feature = "metadata-collector-lint")]
 +mod deprecated_lints;
 +#[cfg_attr(
 +    any(feature = "internal-lints", feature = "metadata-collector-lint"),
 +    allow(clippy::missing_clippy_version_attribute)
 +)]
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod absurd_extreme_comparisons;
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod async_yields_async;
 +mod attrs;
 +mod await_holding_invalid;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod bool_assert_comparison;
 +mod booleans;
 +mod bytecount;
 +mod cargo_common_metadata;
 +mod case_sensitive_file_extension_comparisons;
 +mod casts;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod collapsible_match;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod default_numeric_fallback;
 +mod dereference;
 +mod derivable_impls;
 +mod derive;
 +mod disallowed_methods;
 +mod disallowed_script_idents;
 +mod disallowed_types;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duration_subsec;
 +mod else_if_without_else;
 +mod empty_enum;
 +mod entry;
 +mod enum_clike;
 +mod enum_variants;
 +mod eq_op;
 +mod equatable_if_let;
 +mod erasing_op;
 +mod escape;
 +mod eta_reduction;
 +mod eval_order_dependence;
 +mod excessive_bools;
 +mod exhaustive_items;
 +mod exit;
 +mod explicit_write;
 +mod fallible_impl_from;
 +mod feature_name;
 +mod float_equality_without_abs;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod format_args;
 +mod formatting;
 +mod from_over_into;
 +mod from_str_radix_10;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_not_else;
 +mod if_then_some_else_none;
 +mod implicit_hasher;
 +mod implicit_return;
 +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 int_plus_one;
 +mod integer_division;
 +mod invalid_upcast_comparisons;
 +mod items_after_statements;
 +mod iter_not_returning_iterator;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +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_map;
 +mod manual_non_exhaustive;
 +mod manual_ok_or;
 +mod manual_strip;
 +mod manual_unwrap_or;
 +mod map_clone;
 +mod map_err_ignore;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod match_result_ok;
 +mod match_str_case_mismatch;
 +mod matches;
 +mod mem_forget;
 +mod mem_replace;
 +mod methods;
 +mod minmax;
 +mod misc;
 +mod misc_early;
 +mod missing_const_for_fn;
 +mod missing_doc;
 +mod missing_enforced_import_rename;
 +mod missing_inline;
 +mod module_style;
 +mod modulo_arithmetic;
 +mod multiple_crate_versions;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_mutex_lock;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bitwise_bool;
 +mod needless_bool;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_for_each;
 +mod needless_late_init;
 +mod needless_option_as_deref;
 +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 open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod pass_by_ref_or_value;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_eq;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +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 repeat_once;
 +mod return_self_not_must_use;
 +mod returns;
 +mod same_name_method;
 +mod self_assignment;
 +mod self_named_constructors;
 +mod semicolon_if_nothing_returned;
 +mod serde_api;
 +mod shadow;
 +mod single_component_path_imports;
 +mod size_of_in_element_count;
 +mod slow_vector_initialization;
 +mod stable_sort_primitive;
 +mod strings;
 +mod strlen_on_c_strings;
 +mod suspicious_operation_groupings;
 +mod suspicious_trait_impl;
 +mod swap;
 +mod tabs_in_doc_comments;
 +mod temporary_assignment;
 +mod to_digit_is_some;
 +mod to_string_in_display;
 +mod trailing_empty_array;
 +mod trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod try_err;
 +mod types;
 +mod undocumented_unsafe_blocks;
 +mod undropped_manually_drops;
 +mod unicode;
 +mod uninit_vec;
 +mod unit_hash;
 +mod unit_return_expecting_ord;
 +mod unit_types;
 +mod unnamed_address;
 +mod unnecessary_self_imports;
 +mod unnecessary_sort_by;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_async;
 +mod unused_io_amount;
 +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 vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_dependencies;
 +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`
 +
 +pub use crate::utils::conf::Conf;
 +use crate::utils::conf::TryConf;
 +
 +/// 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 = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!(
 +                "error reading Clippy's configuration file. `{}` is not a valid Rust version",
 +                s
 +            ));
 +            None
 +        })
 +    });
 +
 +    store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
 +    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
 +    store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro));
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(sess: &Session) -> Conf {
 +    let file_name = match utils::conf::lookup_conf_file() {
 +        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 } = 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.struct_err(&format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            error
 +        ))
 +        .emit();
 +    }
 +
 +    conf
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
 +    include!("lib.deprecated.rs");
 +
 +    include!("lib.register_lints.rs");
 +    include!("lib.register_restriction.rs");
 +    include!("lib.register_pedantic.rs");
 +
 +    #[cfg(feature = "internal-lints")]
 +    include!("lib.register_internal.rs");
 +
 +    include!("lib.register_all.rs");
 +    include!("lib.register_style.rs");
 +    include!("lib.register_complexity.rs");
 +    include!("lib.register_correctness.rs");
 +    include!("lib.register_suspicious.rs");
 +    include!("lib.register_perf.rs");
 +    include!("lib.register_cargo.rs");
 +    include!("lib.register_nursery.rs");
 +
 +    #[cfg(feature = "metadata-collector-lint")]
 +    {
 +        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-lints")]
 +    {
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
 +        store.register_late_pass(|| Box::new(utils::inspector::DeepCodeInspector));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
 +    }
 +
 +    store.register_late_pass(|| Box::new(utils::author::Author));
 +    store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
 +    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(needless_bitwise_bool::NeedlessBitwiseBool));
 +    store.register_late_pass(|| Box::new(eq_op::EqOp));
 +    store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
 +    store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move || Box::new(bit_mask::BitMask::new(verbose_bit_mask_threshold)));
 +    store.register_late_pass(|| Box::new(ptr::Ptr));
 +    store.register_late_pass(|| Box::new(ptr_eq::PtrEq));
 +    store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
 +    store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref));
 +    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(misc::MiscLints));
 +    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
 +    store.register_late_pass(|| Box::new(identity_op::IdentityOp));
 +    store.register_late_pass(|| Box::new(erasing_op::ErasingOp));
 +    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(collapsible_match::CollapsibleMatch));
 +    store.register_late_pass(|| Box::new(unicode::Unicode));
 +    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
 +    store.register_late_pass(|| Box::new(unit_hash::UnitHash));
 +    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 = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!(
 +                "error reading Clippy's configuration file. `{}` is not a valid Rust version",
 +                s
 +            ));
 +            None
 +        })
 +    });
 +
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    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)));
 +    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
 +    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::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::new(map_clone::MapClone));
 +    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
 +    store.register_late_pass(|| Box::new(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::new(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(open_options::OpenOptions));
 +    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(no_effect::NoEffect));
 +    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
 +    store.register_late_pass(|| Box::new(transmute::Transmute));
 +    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(get_last_with_len::GetLastWithLen));
 +    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(absurd_extreme_comparisons::AbsurdExtremeComparisons));
 +    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(new_without_default::NewWithoutDefault::default()));
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
 +    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || {
 +        Box::new(functions::Functions::new(
 +            too_many_arguments_threshold,
 +            too_many_lines_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(arithmetic::Arithmetic::default()));
 +    store.register_late_pass(|| Box::new(assign_ops::AssignOps));
 +    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
 +    store.register_late_pass(|| Box::new(eval_order_dependence::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(try_err::TryErr));
 +    store.register_late_pass(|| Box::new(bytecount::ByteCount));
 +    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::new(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(double_comparison::DoubleComparisons));
 +    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_late_pass(|| Box::new(duration_subsec::DurationSubsec));
 +    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
 +    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(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
 +    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(transmuting_null::TransmutingNull));
 +    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
 +    store.register_late_pass(|| Box::new(integer_division::IntegerDivision));
 +    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));
 +    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
 +    store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
 +    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
 +    store.register_early_pass(|| Box::new(reference::RefInDeref));
 +    store.register_early_pass(|| Box::new(double_parens::DoubleParens));
 +    store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::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_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 cargo_ignore_publish = conf.cargo_ignore_publish;
 +    store.register_late_pass(move || Box::new(cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)));
 +    store.register_late_pass(|| Box::new(multiple_crate_versions::MultipleCrateVersions));
 +    store.register_late_pass(|| Box::new(wildcard_dependencies::WildcardDependencies));
 +    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::new(default::Default::default()));
 +    store.register_late_pass(|| Box::new(unused_self::UnusedSelf));
 +    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::new(single_component_path_imports::SingleComponentPathImports));
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_early_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::new(verbose_file_reads::VerboseFileReads));
 +    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
 +    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
 +    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
 +    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(mut_mutex_lock::MutMutexLock));
 +    store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
 +    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
 +    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
 +    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::new(macro_use::MacroUseImports::default()));
 +    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
 +    store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
 +    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
 +    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
 +    store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
 +    store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
 +    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
 +    store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
 +    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
 +    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
 +    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(undropped_manually_drops::UndroppedManuallyDrops));
 +    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::new(vec_init_then_push::VecInitThenPush::default()));
 +    store.register_late_pass(|| {
 +        Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons)
 +    });
 +    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
 +    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
 +    store.register_late_pass(|| Box::new(manual_map::ManualMap));
 +    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(feature_name::FeatureName));
 +    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::default()));
 +    store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
 +    store.register_late_pass(move || Box::new(format_args::FormatArgs));
 +    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));
 +    // 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) {
 +    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
 +    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
 +    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
 +    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
 +    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
 +    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
 +    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
 +    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
 +    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 +    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 +    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
 +    ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
 +    ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
 +
 +    // uplifted lints
 +    ls.register_renamed("clippy::invalid_ref", "invalid_value");
 +    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
 +    ls.register_renamed("clippy::unused_label", "unused_labels");
 +    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
 +    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
 +    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
 +    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
 +    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
 +    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
 +}
 +
 +// 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 6cda926853438bd63163da747c2d6c1c4f6eafcb,0000000000000000000000000000000000000000..c62fa5e998bd475da630f949ac6198c71ce02a97
mode 100644,000000..100644
--- /dev/null
@@@ -1,455 -1,0 +1,454 @@@
-         if offset.as_str() == "0" {
 +use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet;
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::walk_block;
 +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Pat, PatKind, StmtKind};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_span::symbol::sym;
++use std::fmt::Display;
 +use std::iter::Iterator;
 +
 +/// Checks for for loops that sequentially copy items from one slice-like
 +/// object to another.
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) -> bool {
 +    if let Some(higher::Range {
 +        start: Some(start),
 +        end: Some(end),
 +        limits,
 +    }) = higher::Range::hir(arg)
 +    {
 +        // the var must be a single name
 +        if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
 +            let mut starts = vec![Start {
 +                id: canonical_id,
 +                kind: StartKind::Range,
 +            }];
 +
 +            // This is one of few ways to return different iterators
 +            // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
 +            let mut iter_a = None;
 +            let mut iter_b = None;
 +
 +            if let ExprKind::Block(block, _) = body.kind {
 +                if let Some(loop_counters) = get_loop_counters(cx, block, expr) {
 +                    starts.extend(loop_counters);
 +                }
 +                iter_a = Some(get_assignments(block, &starts));
 +            } else {
 +                iter_b = Some(get_assignment(body));
 +            }
 +
 +            let assignments = iter_a.into_iter().flatten().chain(iter_b.into_iter());
 +
 +            let big_sugg = assignments
 +                // The only statements in the for loops can be indexed assignments from
 +                // indexed retrievals (except increments of loop counters).
 +                .map(|o| {
 +                    o.and_then(|(lhs, rhs)| {
 +                        let rhs = fetch_cloned_expr(rhs);
 +                        if_chain! {
 +                            if let ExprKind::Index(base_left, idx_left) = lhs.kind;
 +                            if let ExprKind::Index(base_right, idx_right) = rhs.kind;
 +                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_left));
 +                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
 +                            if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
 +                            if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
 +
 +                            // Source and destination must be different
 +                            if path_to_local(base_left) != path_to_local(base_right);
 +                            then {
 +                                Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
 +                                    IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
 +                            } else {
 +                                None
 +                            }
 +                        }
 +                    })
 +                })
 +                .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, &dst, &src)))
 +                .collect::<Option<Vec<_>>>()
 +                .filter(|v| !v.is_empty())
 +                .map(|v| v.join("\n    "));
 +
 +            if let Some(big_sugg) = big_sugg {
 +                span_lint_and_sugg(
 +                    cx,
 +                    MANUAL_MEMCPY,
 +                    expr.span,
 +                    "it looks like you're manually copying between slices",
 +                    "try replacing the loop by",
 +                    big_sugg,
 +                    Applicability::Unspecified,
 +                );
 +                return true;
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +fn build_manual_memcpy_suggestion<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    start: &Expr<'_>,
 +    end: &Expr<'_>,
 +    limits: ast::RangeLimits,
 +    dst: &IndexExpr<'_>,
 +    src: &IndexExpr<'_>,
 +) -> String {
 +    fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
-                 if sugg.as_str() == end_str {
++        if offset.to_string() == "0" {
 +            sugg::EMPTY.into()
 +        } else {
 +            offset
 +        }
 +    }
 +
 +    let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
 +        if_chain! {
 +            if let ExprKind::MethodCall(method, _, len_args, _) = end.kind;
 +            if method.ident.name == sym::len;
 +            if len_args.len() == 1;
 +            if let Some(arg) = len_args.get(0);
 +            if path_to_local(arg) == path_to_local(base);
 +            then {
-                 end_str.as_str(),
++                if sugg.to_string() == end_str {
 +                    sugg::EMPTY.into()
 +                } else {
 +                    sugg
 +                }
 +            } else {
 +                match limits {
 +                    ast::RangeLimits::Closed => {
 +                        sugg + &sugg::ONE.into()
 +                    },
 +                    ast::RangeLimits::HalfOpen => sugg,
 +                }
 +            }
 +        }
 +    };
 +
 +    let start_str = Sugg::hir(cx, start, "").into();
 +    let end_str: MinifyingSugg<'_> = Sugg::hir(cx, end, "").into();
 +
 +    let print_offset_and_limit = |idx_expr: &IndexExpr<'_>| match idx_expr.idx {
 +        StartKind::Range => (
 +            print_offset(apply_offset(&start_str, &idx_expr.idx_offset)).into_sugg(),
 +            print_limit(
 +                end,
-                     end_str.as_str(),
++                end_str.to_string().as_str(),
 +                idx_expr.base,
 +                apply_offset(&end_str, &idx_expr.idx_offset),
 +            )
 +            .into_sugg(),
 +        ),
 +        StartKind::Counter { initializer } => {
 +            let counter_start = Sugg::hir(cx, initializer, "").into();
 +            (
 +                print_offset(apply_offset(&counter_start, &idx_expr.idx_offset)).into_sugg(),
 +                print_limit(
 +                    end,
- impl<'a> MinifyingSugg<'a> {
-     fn as_str(&self) -> &str {
-         // HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature
-         // changed and this would now require parentheses.
-         match &self.0 {
-             Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(),
-         }
++                    end_str.to_string().as_str(),
 +                    idx_expr.base,
 +                    apply_offset(&end_str, &idx_expr.idx_offset) + &counter_start - &start_str,
 +                )
 +                .into_sugg(),
 +            )
 +        },
 +    };
 +
 +    let (dst_offset, dst_limit) = print_offset_and_limit(dst);
 +    let (src_offset, src_limit) = print_offset_and_limit(src);
 +
 +    let dst_base_str = snippet(cx, dst.base.span, "???");
 +    let src_base_str = snippet(cx, src.base.span, "???");
 +
 +    let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY {
 +        dst_base_str
 +    } else {
 +        format!(
 +            "{}[{}..{}]",
 +            dst_base_str,
 +            dst_offset.maybe_par(),
 +            dst_limit.maybe_par()
 +        )
 +        .into()
 +    };
 +
 +    format!(
 +        "{}.clone_from_slice(&{}[{}..{}]);",
 +        dst,
 +        src_base_str,
 +        src_offset.maybe_par(),
 +        src_limit.maybe_par()
 +    )
 +}
 +
 +/// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`;
 +/// and also, it avoids subtracting a variable from the same one by replacing it with `0`.
 +/// it exists for the convenience of the overloaded operators while normal functions can do the
 +/// same.
 +#[derive(Clone)]
 +struct MinifyingSugg<'a>(Sugg<'a>);
 +
-         match (self.as_str(), rhs.as_str()) {
++impl Display for MinifyingSugg<'a> {
++    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
++        self.0.fmt(f)
 +    }
++}
 +
++impl<'a> MinifyingSugg<'a> {
 +    fn into_sugg(self) -> Sugg<'a> {
 +        self.0
 +    }
 +}
 +
 +impl<'a> From<Sugg<'a>> for MinifyingSugg<'a> {
 +    fn from(sugg: Sugg<'a>) -> Self {
 +        Self(sugg)
 +    }
 +}
 +
 +impl std::ops::Add for &MinifyingSugg<'static> {
 +    type Output = MinifyingSugg<'static>;
 +    fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
-         match (self.as_str(), rhs.as_str()) {
++        match (self.to_string().as_str(), rhs.to_string().as_str()) {
 +            ("0", _) => rhs.clone(),
 +            (_, "0") => self.clone(),
 +            (_, _) => (&self.0 + &rhs.0).into(),
 +        }
 +    }
 +}
 +
 +impl std::ops::Sub for &MinifyingSugg<'static> {
 +    type Output = MinifyingSugg<'static>;
 +    fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
-         match (self.as_str(), rhs.as_str()) {
++        match (self.to_string().as_str(), rhs.to_string().as_str()) {
 +            (_, "0") => self.clone(),
 +            ("0", _) => (-rhs.0.clone()).into(),
 +            (x, y) if x == y => sugg::ZERO.into(),
 +            (_, _) => (&self.0 - &rhs.0).into(),
 +        }
 +    }
 +}
 +
 +impl std::ops::Add<&MinifyingSugg<'static>> for MinifyingSugg<'static> {
 +    type Output = MinifyingSugg<'static>;
 +    fn add(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
-         match (self.as_str(), rhs.as_str()) {
++        match (self.to_string().as_str(), rhs.to_string().as_str()) {
 +            ("0", _) => rhs.clone(),
 +            (_, "0") => self,
 +            (_, _) => (self.0 + &rhs.0).into(),
 +        }
 +    }
 +}
 +
 +impl std::ops::Sub<&MinifyingSugg<'static>> for MinifyingSugg<'static> {
 +    type Output = MinifyingSugg<'static>;
 +    fn sub(self, rhs: &MinifyingSugg<'static>) -> MinifyingSugg<'static> {
++        match (self.to_string().as_str(), rhs.to_string().as_str()) {
 +            (_, "0") => self,
 +            ("0", _) => (-rhs.0.clone()).into(),
 +            (x, y) if x == y => sugg::ZERO.into(),
 +            (_, _) => (self.0 - &rhs.0).into(),
 +        }
 +    }
 +}
 +
 +/// a wrapper around `MinifyingSugg`, which carries an operator like currying
 +/// so that the suggested code become more efficient (e.g. `foo + -bar` `foo - bar`).
 +struct Offset {
 +    value: MinifyingSugg<'static>,
 +    sign: OffsetSign,
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OffsetSign {
 +    Positive,
 +    Negative,
 +}
 +
 +impl Offset {
 +    fn negative(value: Sugg<'static>) -> Self {
 +        Self {
 +            value: value.into(),
 +            sign: OffsetSign::Negative,
 +        }
 +    }
 +
 +    fn positive(value: Sugg<'static>) -> Self {
 +        Self {
 +            value: value.into(),
 +            sign: OffsetSign::Positive,
 +        }
 +    }
 +
 +    fn empty() -> Self {
 +        Self::positive(sugg::ZERO)
 +    }
 +}
 +
 +fn apply_offset(lhs: &MinifyingSugg<'static>, rhs: &Offset) -> MinifyingSugg<'static> {
 +    match rhs.sign {
 +        OffsetSign::Positive => lhs + &rhs.value,
 +        OffsetSign::Negative => lhs - &rhs.value,
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +enum StartKind<'hir> {
 +    Range,
 +    Counter { initializer: &'hir Expr<'hir> },
 +}
 +
 +struct IndexExpr<'hir> {
 +    base: &'hir Expr<'hir>,
 +    idx: StartKind<'hir>,
 +    idx_offset: Offset,
 +}
 +
 +struct Start<'hir> {
 +    id: HirId,
 +    kind: StartKind<'hir>,
 +}
 +
 +fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
 +    let is_slice = match ty.kind() {
 +        ty::Ref(_, subty, _) => is_slice_like(cx, subty),
 +        ty::Slice(..) | ty::Array(..) => true,
 +        _ => false,
 +    };
 +
 +    is_slice || is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::VecDeque)
 +}
 +
 +fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 +    if_chain! {
 +        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
 +        if method.ident.name == sym::clone;
 +        if args.len() == 1;
 +        if let Some(arg) = args.get(0);
 +        then { arg } else { expr }
 +    }
 +}
 +
 +fn get_details_from_idx<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    idx: &Expr<'_>,
 +    starts: &[Start<'tcx>],
 +) -> Option<(StartKind<'tcx>, Offset)> {
 +    fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option<StartKind<'tcx>> {
 +        let id = path_to_local(e)?;
 +        starts.iter().find(|start| start.id == id).map(|start| start.kind)
 +    }
 +
 +    fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option<Sugg<'static>> {
 +        match &e.kind {
 +            ExprKind::Lit(l) => match l.node {
 +                ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())),
 +                _ => None,
 +            },
 +            ExprKind::Path(..) if get_start(e, starts).is_none() => Some(Sugg::hir(cx, e, "???")),
 +            _ => None,
 +        }
 +    }
 +
 +    match idx.kind {
 +        ExprKind::Binary(op, lhs, rhs) => match op.node {
 +            BinOpKind::Add => {
 +                let offset_opt = get_start(lhs, starts)
 +                    .and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o)))
 +                    .or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o))));
 +
 +                offset_opt.map(|(s, o)| (s, Offset::positive(o)))
 +            },
 +            BinOpKind::Sub => {
 +                get_start(lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o))))
 +            },
 +            _ => None,
 +        },
 +        ExprKind::Path(..) => get_start(idx, starts).map(|s| (s, Offset::empty())),
 +        _ => None,
 +    }
 +}
 +
 +fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
 +    if let ExprKind::Assign(lhs, rhs, _) = e.kind {
 +        Some((lhs, rhs))
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Get assignments from the given block.
 +/// The returned iterator yields `None` if no assignment expressions are there,
 +/// filtering out the increments of the given whitelisted loop counters;
 +/// because its job is to make sure there's nothing other than assignments and the increments.
 +fn get_assignments<'a, 'tcx>(
 +    Block { stmts, expr, .. }: &'tcx Block<'tcx>,
 +    loop_counters: &'a [Start<'tcx>],
 +) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> + 'a {
 +    // As the `filter` and `map` below do different things, I think putting together
 +    // just increases complexity. (cc #3188 and #4193)
 +    stmts
 +        .iter()
 +        .filter_map(move |stmt| match stmt.kind {
 +            StmtKind::Local(..) | StmtKind::Item(..) => None,
 +            StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
 +        })
 +        .chain((*expr).into_iter())
 +        .filter(move |e| {
 +            if let ExprKind::AssignOp(_, place, _) = e.kind {
 +                path_to_local(place).map_or(false, |id| {
 +                    !loop_counters
 +                        .iter()
 +                        // skip the first item which should be `StartKind::Range`
 +                        // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop.
 +                        .skip(1)
 +                        .any(|counter| counter.id == id)
 +                })
 +            } else {
 +                true
 +            }
 +        })
 +        .map(get_assignment)
 +}
 +
 +fn get_loop_counters<'a, 'tcx>(
 +    cx: &'a LateContext<'tcx>,
 +    body: &'tcx Block<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +) -> Option<impl Iterator<Item = Start<'tcx>> + 'a> {
 +    // Look for variables that are incremented once per loop iteration.
 +    let mut increment_visitor = IncrementVisitor::new(cx);
 +    walk_block(&mut increment_visitor, body);
 +
 +    // For each candidate, check the parent block to see if
 +    // it's initialized to zero at the start of the loop.
 +    get_enclosing_block(cx, expr.hir_id).and_then(|block| {
 +        increment_visitor
 +            .into_results()
 +            .filter_map(move |var_id| {
 +                let mut initialize_visitor = InitializeVisitor::new(cx, expr, var_id);
 +                walk_block(&mut initialize_visitor, block);
 +
 +                initialize_visitor.get_result().map(|(_, _, initializer)| Start {
 +                    id: var_id,
 +                    kind: StartKind::Counter { initializer },
 +                })
 +            })
 +            .into()
 +    })
 +}
index 5b22b64a370e251ea56ff9f1ee1894428b3b03cb,0000000000000000000000000000000000000000..50d80e6a1d224fc2ae05c5b2ec681cd53ee69f10
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,215 @@@
- use rustc_span::hygiene::ExpnKind;
 +use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::in_macro;
 +use clippy_utils::source::snippet;
 +use hir::def::{DefKind, Res};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
- fn in_macro(span: Span) -> bool {
-     span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
- }
 +use rustc_span::{edition::Edition, sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `#[macro_use] use...`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Since the Rust 2018 edition you can import
 +    /// macro's directly, this is considered idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// #[macro_use]
 +    /// use some_macro;
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub MACRO_USE_IMPORTS,
 +    pedantic,
 +    "#[macro_use] is no longer needed"
 +}
 +
 +#[derive(Clone, Debug, PartialEq, Eq)]
 +struct PathAndSpan {
 +    path: String,
 +    span: Span,
 +}
 +
 +/// `MacroRefData` includes the name of the macro.
 +#[derive(Debug, Clone)]
 +pub struct MacroRefData {
 +    name: String,
 +}
 +
 +impl MacroRefData {
 +    pub fn new(name: String) -> Self {
 +        Self { name }
 +    }
 +}
 +
 +#[derive(Default)]
 +#[allow(clippy::module_name_repetitions)]
 +pub struct MacroUseImports {
 +    /// the actual import path used and the span of the attribute above it.
 +    imports: Vec<(String, Span)>,
 +    /// the span of the macro reference, kept to ensure only one reference is used per macro call.
 +    collected: FxHashSet<Span>,
 +    mac_refs: Vec<MacroRefData>,
 +}
 +
 +impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
 +
 +impl MacroUseImports {
 +    fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) {
 +        let call_site = span.source_callsite();
 +        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
 +        if span.source_callee().is_some() && !self.collected.contains(&call_site) {
 +            let name = if name.contains("::") {
 +                name.split("::").last().unwrap().to_string()
 +            } else {
 +                name.to_string()
 +            };
 +
 +            self.mac_refs.push(MacroRefData::new(name));
 +            self.collected.insert(call_site);
 +        }
 +    }
 +
 +    fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) {
 +        let call_site = span.source_callsite();
 +        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
 +        if span.source_callee().is_some() && !self.collected.contains(&call_site) {
 +            self.mac_refs.push(MacroRefData::new(name.to_string()));
 +            self.collected.insert(call_site);
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 +        if_chain! {
 +            if cx.sess().opts.edition >= Edition::Edition2018;
 +            if let hir::ItemKind::Use(path, _kind) = &item.kind;
 +            let attrs = cx.tcx.hir().attrs(item.hir_id());
 +            if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
 +            if let Res::Def(DefKind::Mod, id) = path.res;
 +            if !id.is_local();
 +            then {
 +                for kid in cx.tcx.item_children(id).iter() {
 +                    if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
 +                        let span = mac_attr.span;
 +                        let def_path = cx.tcx.def_path_str(mac_id);
 +                        self.imports.push((def_path, span));
 +                    }
 +                }
 +            } else {
 +                if in_macro(item.span) {
 +                    self.push_unique_macro_pat_ty(cx, item.span);
 +                }
 +            }
 +        }
 +    }
 +    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
 +        if in_macro(attr.span) {
 +            self.push_unique_macro(cx, attr.span);
 +        }
 +    }
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
 +        if in_macro(expr.span) {
 +            self.push_unique_macro(cx, expr.span);
 +        }
 +    }
 +    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
 +        if in_macro(stmt.span) {
 +            self.push_unique_macro(cx, stmt.span);
 +        }
 +    }
 +    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
 +        if in_macro(pat.span) {
 +            self.push_unique_macro_pat_ty(cx, pat.span);
 +        }
 +    }
 +    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
 +        if in_macro(ty.span) {
 +            self.push_unique_macro_pat_ty(cx, ty.span);
 +        }
 +    }
 +    #[allow(clippy::too_many_lines)]
 +    fn check_crate_post(&mut self, cx: &LateContext<'_>) {
 +        let mut used = FxHashMap::default();
 +        let mut check_dup = vec![];
 +        for (import, span) in &self.imports {
 +            let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));
 +
 +            if let Some(idx) = found_idx {
 +                self.mac_refs.remove(idx);
 +                let seg = import.split("::").collect::<Vec<_>>();
 +
 +                match seg.as_slice() {
 +                    // an empty path is impossible
 +                    // a path should always consist of 2 or more segments
 +                    [] | [_] => return,
 +                    [root, item] => {
 +                        if !check_dup.contains(&(*item).to_string()) {
 +                            used.entry(((*root).to_string(), span))
 +                                .or_insert_with(Vec::new)
 +                                .push((*item).to_string());
 +                            check_dup.push((*item).to_string());
 +                        }
 +                    },
 +                    [root, rest @ ..] => {
 +                        if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
 +                            let filtered = rest
 +                                .iter()
 +                                .filter_map(|item| {
 +                                    if check_dup.contains(&(*item).to_string()) {
 +                                        None
 +                                    } else {
 +                                        Some((*item).to_string())
 +                                    }
 +                                })
 +                                .collect::<Vec<_>>();
 +                            used.entry(((*root).to_string(), span))
 +                                .or_insert_with(Vec::new)
 +                                .push(filtered.join("::"));
 +                            check_dup.extend(filtered);
 +                        } else {
 +                            let rest = rest.to_vec();
 +                            used.entry(((*root).to_string(), span))
 +                                .or_insert_with(Vec::new)
 +                                .push(rest.join("::"));
 +                            check_dup.extend(rest.iter().map(ToString::to_string));
 +                        }
 +                    },
 +                }
 +            }
 +        }
 +
 +        let mut suggestions = vec![];
 +        for ((root, span), path) in used {
 +            if path.len() == 1 {
 +                suggestions.push((span, format!("{}::{}", root, path[0])));
 +            } else {
 +                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
 +            }
 +        }
 +
 +        // If mac_refs is not empty we have encountered an import we could not handle
 +        // such as `std::prelude::v1::foo` or some other macro that expands to an import.
 +        if self.mac_refs.is_empty() {
 +            for (span, import) in suggestions {
 +                let help = format!("use {};", import);
 +                span_lint_and_sugg(
 +                    cx,
 +                    MACRO_USE_IMPORTS,
 +                    *span,
 +                    "`macro_use` attributes are no longer needed in the Rust 2018 edition",
 +                    "remove the attribute and import the macro directly, try",
 +                    help,
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
index dbf103143d93cc7dc3f4e76cd3e1712d44aa9844,0000000000000000000000000000000000000000..2c0fc218ca07c0d5eabb6a3140c540406a938a6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,172 @@@
-             ExprKind::MethodCall(segment, _, [receiver], _)
-                 if self.case_altered(segment.ident.as_str(), receiver) => {},
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::Symbol;
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `match` expressions modifying the case of a string with non-compliant arms
 +    ///
 +    /// ### Why is this bad?
 +    /// The arm is unreachable, which is likely a mistake
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let text = "Foo";
 +    ///
 +    /// match &*text.to_ascii_lowercase() {
 +    ///     "foo" => {},
 +    ///     "Bar" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let text = "Foo";
 +    ///
 +    /// match &*text.to_ascii_lowercase() {
 +    ///     "foo" => {},
 +    ///     "bar" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub MATCH_STR_CASE_MISMATCH,
 +    correctness,
 +    "creation of a case altering match expression with non-compliant arms"
 +}
 +
 +declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
 +
 +#[derive(Debug)]
 +enum CaseMethod {
 +    LowerCase,
 +    AsciiLowerCase,
 +    UpperCase,
 +    AsciiUppercase,
 +}
 +
 +impl LateLintPass<'_> for MatchStrCaseMismatch {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.tcx.sess, expr.span);
 +            if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
 +            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
 +            if let ty::Str = ty.kind();
 +            then {
 +                let mut visitor = MatchExprVisitor {
 +                    cx,
 +                    case_method: None,
 +                };
 +
 +                visitor.visit_expr(match_expr);
 +
 +                if let Some(case_method) = visitor.case_method {
 +                    if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
 +                        lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct MatchExprVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    case_method: Option<CaseMethod>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
 +        match ex.kind {
-             if !case_check(&input);
++            ExprKind::MethodCall(segment, _, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {
++            },
 +            _ => walk_expr(self, ex),
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
 +    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
 +        if let Some(case_method) = get_case_method(segment_ident) {
 +            let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 +
 +            if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
 +                self.case_method = Some(case_method);
 +                return true;
 +            }
 +        }
 +
 +        false
 +    }
 +}
 +
 +fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
 +    match segment_ident_str {
 +        "to_lowercase" => Some(CaseMethod::LowerCase),
 +        "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
 +        "to_uppercase" => Some(CaseMethod::UpperCase),
 +        "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
 +        _ => None,
 +    }
 +}
 +
 +fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, Symbol)> {
 +    let case_check = match case_method {
 +        CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
 +        CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
 +        CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
 +        CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
 +    };
 +
 +    for arm in arms {
 +        if_chain! {
 +            if let PatKind::Lit(Expr {
 +                                kind: ExprKind::Lit(lit),
 +                                ..
 +                            }) = arm.pat.kind;
 +            if let LitKind::Str(symbol, _) = lit.node;
 +            let input = symbol.as_str();
++            if !case_check(input);
 +            then {
 +                return Some((lit.span, symbol));
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
 +    let (method_str, suggestion) = match case_method {
 +        CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
 +        CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
 +        CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
 +        CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        MATCH_STR_CASE_MISMATCH,
 +        bad_case_span,
 +        "this `match` arm has a differing case than its expression",
 +        &*format!("consider changing the case of this arm to respect `{}`", method_str),
 +        format!("\"{}\"", suggestion),
 +        Applicability::MachineApplicable,
 +    );
 +}
index e32594757d0caa929da4a608e335baad4b527d42,0000000000000000000000000000000000000000..f5410c7fd7fc808cab894f0ba762cc20919d3a72
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,46 @@@
- use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::is_trait_method;
++use clippy_utils::path_to_local;
 +use clippy_utils::source::snippet;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
++use rustc_hir::{BindingAnnotation, Node, PatKind};
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +use super::ITER_SKIP_NEXT;
 +
 +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
 +    // lint if caller of skip is an Iterator
 +    if is_trait_method(cx, expr, sym::Iterator) {
-         span_lint_and_sugg(
++        let mut application = Applicability::MachineApplicable;
++        span_lint_and_then(
 +            cx,
 +            ITER_SKIP_NEXT,
 +            expr.span.trim_start(recv.span).unwrap(),
 +            "called `skip(..).next()` on an iterator",
-             "use `nth` instead",
-             format!(".nth({})", snippet(cx, arg.span, "..")),
-             Applicability::MachineApplicable,
++            |diag| {
++                if_chain! {
++                    if let Some(id) = path_to_local(recv);
++                    if let Node::Binding(pat) = cx.tcx.hir().get(id);
++                    if let PatKind::Binding(ann, _, _, _)  = pat.kind;
++                    if ann != BindingAnnotation::Mutable;
++                    then {
++                        application = Applicability::Unspecified;
++                        diag.span_help(
++                            pat.span,
++                            &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
++                        );
++                    }
++                }
++
++                diag.span_suggestion(
++                    expr.span.trim_start(recv.span).unwrap(),
++                    "use `nth` instead",
++                    format!(".nth({})", snippet(cx, arg.span, "..")),
++                    application,
++                );
++            },
 +        );
 +    }
 +}
index 4934240abfc46c2feca8983bf17bab4a4758abc7,0000000000000000000000000000000000000000..4e33b2ff14cdeaa2e3d7427e5349c30c2f22a5d5
mode 100644,000000..100644
--- /dev/null
@@@ -1,2591 -1,0 +1,2591 @@@
-                         &name,
 +mod bind_instead_of_map;
 +mod bytes_nth;
 +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 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_unwrap;
 +mod implicit_clone;
 +mod inefficient_to_string;
 +mod inspect_for_each;
 +mod into_iter_on_ref;
 +mod iter_cloned_collect;
 +mod iter_count;
 +mod iter_next_slice;
 +mod iter_nth;
 +mod iter_nth_zero;
 +mod iter_skip_next;
 +mod iterator_step_by_zero;
 +mod manual_saturating_arithmetic;
 +mod manual_str_repeat;
 +mod map_collect_result_unit;
 +mod map_flatten;
 +mod map_identity;
 +mod map_unwrap_or;
 +mod ok_expect;
 +mod option_as_ref_deref;
 +mod option_map_or_none;
 +mod option_map_unwrap_or;
 +mod or_fun_call;
 +mod search_is_some;
 +mod single_char_add_str;
 +mod single_char_insert_string;
 +mod single_char_pattern;
 +mod single_char_push_string;
 +mod skip_while_next;
 +mod str_splitn;
 +mod string_extend_chars;
 +mod suspicious_map;
 +mod suspicious_splitn;
 +mod uninit_assumed_init;
 +mod unnecessary_filter_map;
 +mod unnecessary_fold;
 +mod unnecessary_iter_cloned;
 +mod unnecessary_lazy_eval;
 +mod unnecessary_to_owned;
 +mod unwrap_or_else_default;
 +mod unwrap_used;
 +mod useless_asref;
 +mod utils;
 +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::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
 +use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::def::Res;
 +use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::Symbol;
 +use rustc_span::{sym, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +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 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()` calls on `Option`s and on `Result`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 opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.unwrap();
 +    ///
 +    /// // Good
 +    /// opt.expect("more helpful message");
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.unwrap();
 +    ///
 +    /// // Good
 +    /// res.expect("more helpful message");
 +    /// ```
 +    #[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()` calls on `Option`s and `Result`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 opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.expect("one");
 +    ///
 +    /// // Good
 +    /// let opt = Some(1);
 +    /// opt?;
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.expect("one");
 +    ///
 +    /// // Good
 +    /// res?;
 +    /// # Ok::<(), ()>(())
 +    /// ```
 +    #[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       |`&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::<_, ()>(());
 +    ///
 +    /// // Bad
 +    /// x.ok().expect("why did I do this again?");
 +    ///
 +    /// // Good
 +    /// 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 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);
 +    ///
 +    /// // Bad
 +    /// x.unwrap_or_else(Default::default);
 +    /// x.unwrap_or_else(u32::default);
 +    ///
 +    /// // Good
 +    /// 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 x = Some(1);
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or(0);
 +    ///
 +    /// // Good
 +    /// x.map_or(0, |a| a + 1);
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let x: Result<usize, ()> = Ok(1);
 +    /// # fn some_function(foo: ()) -> usize { 1 }
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or_else(some_function);
 +    ///
 +    /// // Good
 +    /// x.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);
 +    ///
 +    /// // Bad
 +    /// opt.map_or(None, |a| Some(a + 1));
 +    ///
 +    /// // Good
 +    /// 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
 +    /// Bad:
 +    /// ```rust
 +    /// # let r: Result<u32, &str> = Ok(1);
 +    /// assert_eq!(Some(1), r.map_or(None, Some));
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```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();
 +    /// ```
 +    /// Could be written as
 +    /// ```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();
 +    /// ```
 +    /// Could be written as
 +    /// ```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(_)`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![vec![1]];
 +    ///
 +    /// // Bad
 +    /// vec.iter().map(|x| x.iter()).flatten();
 +    ///
 +    /// // Good
 +    /// vec.iter().flat_map(|x| x.iter());
 +    /// ```
 +    #[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
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .filter(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// (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
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .find(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```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
 +    /// let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0).is_some();
 +    ///
 +    /// let _ = "hello world".find("world").is_none();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().any(|x| *x == 0);
 +    ///
 +    /// let _ = !"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('_') {};
 +    /// ```
 +    /// Could be written as
 +    /// ```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(..))`,
 +    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
 +    /// `unwrap_or_default` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// The function will always be called and potentially
 +    /// allocate an object acting as the default.
 +    ///
 +    /// ### 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 anyway.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or(String::new());
 +    /// ```
 +    /// this can instead be written:
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or_else(String::new);
 +    /// ```
 +    /// or
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or_default();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OR_FUN_CALL,
 +    perf,
 +    "using any `*or` method with a function call, which suggests `*or_else`"
 +}
 +
 +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
 +    /// ```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).as_str());
 +    /// ```
 +    /// this can instead be written:
 +    /// ```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);
 +    ///
 +    /// // Bad
 +    /// x.clone();
 +    ///
 +    /// // Good
 +    /// 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
 +    /// // Bad
 +    /// _.split("x");
 +    ///
 +    /// // Good
 +    /// _.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;
 +    /// // Bad
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().nth(0);
 +    ///
 +    /// // Good
 +    /// # 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 `.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];
 +    ///
 +    /// // Bad
 +    /// a.extend(b.drain(..));
 +    ///
 +    /// // Good
 +    /// 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 vecor 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 = "_";
 +    ///
 +    /// // Bad
 +    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
 +    ///
 +    /// // Good
 +    /// 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
 +    /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
 +    /// ```
 +    /// This could be written as:
 +    /// ```rust
 +    /// let _ = (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 which 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 `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
 +    /// // Bad
 +    /// let _ = (&vec![3, 4, 5]).into_iter();
 +    ///
 +    /// // Good
 +    /// let _ = (&vec![3, 4, 5]).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,
 +    "`.chcked_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 it's 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");
 +    /// ```
 +    /// Could be written as
 +    /// ```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
 +    /// use std::iter::FromIterator;
 +    ///
 +    /// 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.52.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
 +    /// // Bad
 +    /// let _ = "Hello".bytes().nth(3);
 +    ///
 +    /// // Good
 +    /// let _ = "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
 +    /// // Bad
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.iter().count();
 +    /// let _ = &some_vec[..].iter().count();
 +    ///
 +    /// // Good
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.len();
 +    /// let _ = &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 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
 +    /// // Bad
 +    /// let s = "";
 +    /// for x in s.splitn(1, ":") {
 +    ///     // use x
 +    /// }
 +    ///
 +    /// // Good
 +    /// let s = "";
 +    /// for x in s.splitn(2, ":") {
 +    ///     // use x
 +    /// }
 +    /// ```
 +    #[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
 +    /// // Bad
 +    /// let x: String = std::iter::repeat('x').take(10).collect();
 +    ///
 +    /// // Good
 +    /// 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
 +    /// // Bad
 +    ///  let (key, value) = _.splitn(2, '=').next_tuple()?;
 +    ///  let value = _.splitn(2, '=').nth(1)?;
 +    ///
 +    /// // Good
 +    /// let (key, value) = _.split_once('=')?;
 +    /// let value = _.split_once('=')?.1;
 +    /// ```
 +    #[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
 +    /// // Bad
 +    /// let str = "key=value=add";
 +    /// let _ = str.splitn(3, '=').next().unwrap();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // Good
 +    /// let str = "key=value=add";
 +    /// let _ = str.split('=').next().unwrap();
 +    /// ```
 +    #[clippy::version = "1.58.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.
 +    ///
 +    /// ### 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.58.0"]
 +    pub UNNECESSARY_TO_OWNED,
 +    perf,
 +    "unnecessary calls to `to_owned`-like functions"
 +}
 +
 +pub struct Methods {
 +    avoid_breaking_exported_api: bool,
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl Methods {
 +    #[must_use]
 +    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            avoid_breaking_exported_api,
 +            msrv,
 +        }
 +    }
 +}
 +
 +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,
 +    EXPECT_FUN_CALL,
 +    CHARS_NEXT_CMP,
 +    CHARS_LAST_CMP,
 +    CLONE_ON_COPY,
 +    CLONE_ON_REF_PTR,
 +    CLONE_DOUBLE_REF,
 +    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,
 +    STRING_EXTEND_CHARS,
 +    ITER_CLONED_COLLECT,
 +    USELESS_ASREF,
 +    UNNECESSARY_FOLD,
 +    UNNECESSARY_FILTER_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_SPLITN,
 +    MANUAL_STR_REPEAT,
 +    EXTEND_WITH_DRAIN,
 +    MANUAL_SPLIT_ONCE,
 +    NEEDLESS_SPLITN,
 +    UNNECESSARY_TO_OWNED,
 +]);
 +
 +/// Extracts a method call name, args, and `Span` of the method name.
 +fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(Symbol, &'tcx [hir::Expr<'tcx>], Span)> {
 +    if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
 +        if !args.iter().any(|e| e.span.from_expansion()) {
 +            return Some((path.ident.name, args, span));
 +        }
 +    }
 +    None
 +}
 +
 +/// Same as `method_call` but the `Symbol` is dereferenced into a temporary `&str`
 +macro_rules! method_call {
 +    ($expr:expr) => {
 +        method_call($expr)
 +            .as_ref()
 +            .map(|&(ref name, args, span)| (name.as_str(), args, span))
 +    };
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Methods {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        check_methods(cx, expr, self.msrv.as_ref());
 +
 +        match expr.kind {
 +            hir::ExprKind::Call(func, args) => {
 +                from_iter_instead_of_collect::check(cx, expr, args, func);
 +            },
 +            hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
 +                or_fun_call::check(cx, expr, *method_span, method_call.ident.as_str(), args);
 +                expect_fun_call::check(cx, expr, *method_span, method_call.ident.as_str(), args);
 +                clone_on_copy::check(cx, expr, method_call.ident.name, args);
 +                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
 +                inefficient_to_string::check(cx, expr, method_call.ident.name, args);
 +                single_char_add_str::check(cx, expr, args);
 +                into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
 +                single_char_pattern::check(cx, expr, method_call.ident.name, args);
 +                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
 +            },
 +            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_did(impl_item.hir_id());
 +        let item = cx.tcx.hir().expect_item(parent);
 +        let self_ty = cx.tcx.type_of(item.def_id);
 +
 +        let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
 +        if_chain! {
 +            if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
 +            if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
 +
 +            let method_sig = cx.tcx.fn_sig(impl_item.def_id);
 +            let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
 +
 +            let first_arg_ty = &method_sig.inputs().iter().next();
 +
 +            // check conventions w.r.t. conversion method names and predicates
 +            if let Some(first_arg_ty) = first_arg_ty;
 +
 +            then {
 +                // if this impl block implements a trait, lint in trait definition instead
 +                if !implements_trait && cx.access_levels.is_exported(impl_item.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) &&
 +                            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.access_levels.is_exported(impl_item.def_id))
 +                {
 +                    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());
 +
 +            // walk the return type and check for Self (this does not check associated types)
 +            if let Some(self_adt) = self_ty.ty_adt_def() {
 +                if contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
 +                    return;
 +                }
 +            } else if contains_ty(cx.tcx, ret_ty, self_ty) {
 +                return;
 +            }
 +
 +            // if return type is impl trait, check the associated types
 +            if let ty::Opaque(def_id, _) = *ret_ty.kind() {
 +                // one of the associated types must be Self
 +                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
 +                    if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
 +                        // walk the associated type and check for Self
 +                        if let Some(self_adt) = self_ty.ty_adt_def() {
 +                            if contains_adt_constructor(cx.tcx, projection_predicate.ty, self_adt) {
 +                                return;
 +                            }
 +                        } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +
 +            if name == "new" && !TyS::same_type(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.def_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.def_id.to_def_id()).self_ty().skip_binder();
 +            if !contains_ty(cx.tcx, ret_ty, self_ty);
 +
 +            then {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
 +    if let Some((name, [recv, args @ ..], 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_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, msrv),
 +            ("collect", []) => 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, recv);
 +                },
 +                Some(("take", [take_self_arg, take_arg], _)) => {
 +                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
 +                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
 +                    }
 +                },
 +                _ => {},
 +            },
 +            ("count", []) => match method_call!(recv) {
 +                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
 +                    iter_count::check(cx, expr, recv2, name);
 +                },
 +                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
 +                _ => {},
 +            },
 +            ("expect", [_]) => match method_call!(recv) {
 +                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
 +                _ => expect_used::check(cx, expr, recv),
 +            },
 +            ("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);
 +                filter_map_identity::check(cx, expr, arg, span);
 +            },
 +            ("flat_map", [arg]) => {
 +                flat_map_identity::check(cx, expr, arg, span);
 +                flat_map_option::check(cx, expr, arg, span);
 +            },
 +            ("flatten", []) => {
 +                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
 +                    map_flatten::check(cx, expr, recv, map_arg);
 +                }
 +            },
 +            ("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_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
 +            ("is_file", []) => filetype_is_file::check(cx, expr, recv),
 +            ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
 +            ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
 +            ("map", [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, msrv),
 +                        ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, 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, span);
 +            },
 +            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
 +            ("next", []) => {
 +                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
 +                    match (name, args) {
 +                        ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
 +                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
 +                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
 +                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, 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(("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"),
 +            ("or_else", [arg]) => {
 +                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
 +                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
 +                }
 +            },
 +            ("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);
 +                    if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
 +                        str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg);
 +                    }
 +                    if count >= 2 {
 +                        str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count);
 +                    }
 +                }
 +            },
 +            ("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),
 +            ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
 +                implicit_clone::check(cx, name, expr, recv, span);
 +            },
 +            ("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),
 +                _ => unwrap_used::check(cx, expr, recv),
 +            },
 +            ("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);
 +                },
 +                _ => {},
 +            },
 +            ("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, msrv) => {},
 +                _ => {
 +                    unwrap_or_else_default::check(cx, expr, recv, u_arg);
 +                    unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
 +                },
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +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),
 +    // FIXME: default doesn't work
 +    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, Debug)]
 +enum SelfKind {
 +    Value,
 +    Ref,
 +    RefMut,
 +    No,
 +}
 +
 +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<'_>, ty: Ty<'_>) -> 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_path = match mutability {
 +                hir::Mutability::Not => &paths::ASREF_TRAIT,
 +                hir::Mutability::Mut => &paths::ASMUT_TRAIT,
 +            };
 +
 +            let trait_def_id = match get_trait_def_id(cx, trait_path) {
 +                Some(did) => did,
 +                None => return false,
 +            };
 +            implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
 +        }
 +
 +        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 => ty != parent_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 is_bool(ty: &hir::Ty<'_>) -> bool {
 +    if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +        matches!(path.res, Res::PrimTy(PrimTy::Bool))
 +    } else {
 +        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 276467b1dfdbff4a4a4e997651b3e3187ee44e6e,0000000000000000000000000000000000000000..f3af281d6cacc289838d278b25d9d3ed144d4494
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,46 @@@
-     diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
 +//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
 +
 +use super::UNWRAP_OR_ELSE_DEFAULT;
 +use clippy_utils::{
-         if is_trait_item(cx, u_arg, sym::Default);
++    diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
++    ty::is_type_diagnostic_item,
 +};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    recv: &'tcx hir::Expr<'_>,
 +    u_arg: &'tcx hir::Expr<'_>,
 +) {
 +    // something.unwrap_or_else(Default::default)
 +    // ^^^^^^^^^- recv          ^^^^^^^^^^^^^^^^- u_arg
 +    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
 +    let recv_ty = cx.typeck_results().expr_ty(recv);
 +    let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
 +    let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
 +
 +    if_chain! {
 +        if is_option || is_result;
++        if is_default_equivalent_call(cx, u_arg);
 +        then {
 +            let mut applicability = Applicability::MachineApplicable;
 +
 +            span_lint_and_sugg(
 +                cx,
 +                UNWRAP_OR_ELSE_DEFAULT,
 +                expr.span,
 +                "use of `.unwrap_or_else(..)` to construct default value",
 +                "try",
 +                format!(
 +                    "{}.unwrap_or_default()",
 +                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
 +                ),
 +                applicability,
 +            );
 +        }
 +    }
 +}
index 11ad881ee7b95bf1d29b58b89111e85a58b575b7,0000000000000000000000000000000000000000..24b44f819f41997df804161082b5e7e5a7887ac0
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,81 @@@
-             let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_span::symbol::sym;
 +
 +pub(super) fn derefs_to_slice<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'tcx>,
 +    ty: Ty<'tcx>,
 +) -> Option<&'tcx hir::Expr<'tcx>> {
 +    fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
 +        match ty.kind() {
 +            ty::Slice(_) => true,
 +            ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
 +            ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
 +            ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(),
 +            ty::Ref(_, inner, _) => may_slice(cx, inner),
 +            _ => false,
 +        }
 +    }
 +
 +    if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind {
 +        if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
 +            Some(self_arg)
 +        } else {
 +            None
 +        }
 +    } else {
 +        match ty.kind() {
 +            ty::Slice(_) => Some(expr),
 +            ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
 +            ty::Ref(_, inner, _) => {
 +                if may_slice(cx, inner) {
 +                    Some(expr)
 +                } else {
 +                    None
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +}
 +
 +pub(super) fn get_hint_if_single_char_arg(
 +    cx: &LateContext<'_>,
 +    arg: &hir::Expr<'_>,
 +    applicability: &mut Applicability,
 +) -> Option<String> {
 +    if_chain! {
 +        if let hir::ExprKind::Lit(lit) = &arg.kind;
 +        if let ast::LitKind::Str(r, style) = lit.node;
 +        let string = r.as_str();
 +        if string.chars().count() == 1;
 +        then {
++            let snip = snippet_with_applicability(cx, arg.span, string, applicability);
 +            let ch = if let ast::StrStyle::Raw(nhash) = style {
 +                let nhash = nhash as usize;
 +                // for raw string: r##"a"##
 +                &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
 +            } else {
 +                // for regular string: "a"
 +                &snip[1..(snip.len() - 1)]
 +            };
 +
 +            let hint = format!("'{}'", match ch {
 +                "'" => "\\'" ,
 +                r"\" => "\\\\",
 +                _ => ch,
 +            });
 +
 +            Some(hint)
 +        } else {
 +            None
 +        }
 +    }
 +}
index d391fbecf82e14ea9b2cffde2267704bd6f8ecf4,0000000000000000000000000000000000000000..778d49cb4b6ed1634cc1024bfad5e3d6883376bb
mode 100644,000000..100644
--- /dev/null
@@@ -1,380 -1,0 +1,380 @@@
-                         |h: Sugg<'_>| !h,
 +//! Checks for needless boolean results of if-else expressions
 +//!
 +//! This lint is **warn** by default
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 +use clippy_utils::higher;
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions of the form `if c { true } else {
 +    /// false }` (or vice versa) and suggests using the condition directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code.
 +    ///
 +    /// ### Known problems
 +    /// Maybe false positives: Sometimes, the two branches are
 +    /// painstakingly documented (which we, of course, do not detect), so they *may*
 +    /// have some value. Even then, the documentation can be rewritten to match the
 +    /// shorter code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// if x {
 +    ///     false
 +    /// } else {
 +    ///     true
 +    /// }
 +    /// ```
 +    /// Could be written as
 +    /// ```rust,ignore
 +    /// !x
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEEDLESS_BOOL,
 +    complexity,
 +    "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions of the form `x == true`,
 +    /// `x != true` and order comparisons such as `x < true` (or vice versa) and
 +    /// suggest using the variable directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// Unnecessary code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// if x == true {}
 +    /// if y == false {}
 +    /// ```
 +    /// use `x` directly:
 +    /// ```rust,ignore
 +    /// if x {}
 +    /// if !y {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub BOOL_COMPARISON,
 +    complexity,
 +    "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 +}
 +
 +declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
 +
 +fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
 +    let mut inner = e;
 +    while let ExprKind::Binary(_, i, _)
 +    | ExprKind::Call(i, _)
 +    | ExprKind::Cast(i, _)
 +    | ExprKind::Type(i, _)
 +    | ExprKind::Index(i, _) = inner.kind
 +    {
 +        if matches!(
 +            i.kind,
 +            ExprKind::Block(..)
 +                | ExprKind::ConstBlock(..)
 +                | ExprKind::If(..)
 +                | ExprKind::Loop(..)
 +                | ExprKind::Match(..)
 +        ) {
 +            return true;
 +        }
 +        inner = i;
 +    }
 +    false
 +}
 +
 +fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
 +    matches!(
 +        get_parent_node(cx.tcx, id),
 +        Some(Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }))
 +    )
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        use self::Expression::{Bool, RetBool};
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let Some(higher::If {
 +            cond,
 +            then,
 +            r#else: Some(r#else),
 +        }) = higher::If::hir(e)
 +        {
 +            let reduce = |ret, not| {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let snip = Sugg::hir_with_applicability(cx, cond, "<predicate>", &mut applicability);
 +                let mut snip = if not { !snip } else { snip };
 +
 +                if ret {
 +                    snip = snip.make_return();
 +                }
 +
 +                if is_else_clause(cx.tcx, e) {
 +                    snip = snip.blockify();
 +                }
 +
 +                if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) {
 +                    snip = snip.maybe_par();
 +                }
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    NEEDLESS_BOOL,
 +                    e.span,
 +                    "this if-then-else expression returns a bool literal",
 +                    "you can reduce it to",
 +                    snip.to_string(),
 +                    applicability,
 +                );
 +            };
 +            if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(r#else)?))) {
 +                match (a, b) {
 +                    (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
 +                        span_lint(
 +                            cx,
 +                            NEEDLESS_BOOL,
 +                            e.span,
 +                            "this if-then-else expression will always return true",
 +                        );
 +                    },
 +                    (RetBool(false), RetBool(false)) | (Bool(false), Bool(false)) => {
 +                        span_lint(
 +                            cx,
 +                            NEEDLESS_BOOL,
 +                            e.span,
 +                            "this if-then-else expression will always return false",
 +                        );
 +                    },
 +                    (RetBool(true), RetBool(false)) => reduce(true, false),
 +                    (Bool(true), Bool(false)) => reduce(false, false),
 +                    (RetBool(false), RetBool(true)) => reduce(true, true),
 +                    (Bool(false), Bool(true)) => reduce(false, true),
 +                    _ => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]);
 +
 +impl<'tcx> LateLintPass<'tcx> for BoolComparison {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node, .. }, ..) = e.kind {
 +            let ignore_case = None::<(fn(_) -> _, &str)>;
 +            let ignore_no_literal = None::<(fn(_, _) -> _, &str)>;
 +            match node {
 +                BinOpKind::Eq => {
 +                    let true_case = Some((|h| h, "equality checks against true are unnecessary"));
 +                    let false_case = Some((
-                         |h: Sugg<'_>| !h,
++                        |h: Sugg<'tcx>| !h,
 +                        "equality checks against false can be replaced by a negation",
 +                    ));
 +                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
 +                },
 +                BinOpKind::Ne => {
 +                    let true_case = Some((
-                         |h: Sugg<'_>| !h,
++                        |h: Sugg<'tcx>| !h,
 +                        "inequality checks against true can be replaced by a negation",
 +                    ));
 +                    let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
 +                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
 +                },
 +                BinOpKind::Lt => check_comparison(
 +                    cx,
 +                    e,
 +                    ignore_case,
 +                    Some((|h| h, "greater than checks against false are unnecessary")),
 +                    Some((
-                         |l: Sugg<'_>, r: Sugg<'_>| (!l).bit_and(&r),
++                        |h: Sugg<'tcx>| !h,
 +                        "less than comparison against true can be replaced by a negation",
 +                    )),
 +                    ignore_case,
 +                    Some((
-                         |h: Sugg<'_>| !h,
++                        |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r),
 +                        "order comparisons between booleans can be simplified",
 +                    )),
 +                ),
 +                BinOpKind::Gt => check_comparison(
 +                    cx,
 +                    e,
 +                    Some((
-                         |l: Sugg<'_>, r: Sugg<'_>| l.bit_and(&(!r)),
++                        |h: Sugg<'tcx>| !h,
 +                        "less than comparison against true can be replaced by a negation",
 +                    )),
 +                    ignore_case,
 +                    ignore_case,
 +                    Some((|h| h, "greater than checks against false are unnecessary")),
 +                    Some((
++                        |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)),
 +                        "order comparisons between booleans can be simplified",
 +                    )),
 +                ),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +struct ExpressionInfoWithSpan {
 +    one_side_is_unary_not: bool,
 +    left_span: Span,
 +    right_span: Span,
 +}
 +
 +fn is_unary_not(e: &Expr<'_>) -> (bool, Span) {
 +    if let ExprKind::Unary(UnOp::Not, operand) = e.kind {
 +        return (true, operand.span);
 +    }
 +    (false, e.span)
 +}
 +
 +fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan {
 +    let left = is_unary_not(left_side);
 +    let right = is_unary_not(right_side);
 +
 +    ExpressionInfoWithSpan {
 +        one_side_is_unary_not: left.0 != right.0,
 +        left_span: left.1,
 +        right_span: right.1,
 +    }
 +}
 +
 +fn check_comparison<'a, 'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
 +) {
 +    if let ExprKind::Binary(op, left_side, right_side) = e.kind {
 +        let (l_ty, r_ty) = (
 +            cx.typeck_results().expr_ty(left_side),
 +            cx.typeck_results().expr_ty(right_side),
 +        );
 +        if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() {
 +            return;
 +        }
 +        if l_ty.is_bool() && r_ty.is_bool() {
 +            let mut applicability = Applicability::MachineApplicable;
 +
 +            if op.node == BinOpKind::Eq {
 +                let expression_info = one_side_is_unary_not(left_side, right_side);
 +                if expression_info.one_side_is_unary_not {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        BOOL_COMPARISON,
 +                        e.span,
 +                        "this comparison might be written more concisely",
 +                        "try simplifying it as shown",
 +                        format!(
 +                            "{} != {}",
 +                            snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
 +                            snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
 +                        ),
 +                        applicability,
 +                    );
 +                }
 +            }
 +
 +            match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
 +                (Some(true), None) => left_true.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
 +                }),
 +                (None, Some(true)) => right_true.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
 +                }),
 +                (Some(false), None) => left_false.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
 +                }),
 +                (None, Some(false)) => right_false.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
 +                }),
 +                (None, None) => no_literal.map_or((), |(h, m)| {
 +                    let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
 +                    let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
 +                    span_lint_and_sugg(
 +                        cx,
 +                        BOOL_COMPARISON,
 +                        e.span,
 +                        m,
 +                        "try simplifying it as shown",
 +                        h(left_side, right_side).to_string(),
 +                        applicability,
 +                    );
 +                }),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn suggest_bool_comparison<'a, 'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    expr: &Expr<'_>,
 +    mut applicability: Applicability,
 +    message: &str,
 +    conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
 +) {
 +    let hint = if expr.span.from_expansion() {
 +        if applicability != Applicability::Unspecified {
 +            applicability = Applicability::MaybeIncorrect;
 +        }
 +        Sugg::hir_with_macro_callsite(cx, expr, "..")
 +    } else {
 +        Sugg::hir_with_applicability(cx, expr, "..", &mut applicability)
 +    };
 +    span_lint_and_sugg(
 +        cx,
 +        BOOL_COMPARISON,
 +        e.span,
 +        message,
 +        "try simplifying it as shown",
 +        conv_hint(hint).to_string(),
 +        applicability,
 +    );
 +}
 +
 +enum Expression {
 +    Bool(bool),
 +    RetBool(bool),
 +}
 +
 +fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
 +    match peel_blocks_with_stmt(expr).kind {
 +        ExprKind::Ret(Some(ret)) => Some(Expression::RetBool(fetch_bool_expr(ret)?)),
 +        _ => Some(Expression::Bool(fetch_bool_expr(expr)?)),
 +    }
 +}
 +
 +fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
 +    if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
 +        if let LitKind::Bool(value) = lit_ptr.node {
 +            return Some(value);
 +        }
 +    }
 +    None
 +}
index cb67fab17400590a04c008afd701f66047f64d6a,0000000000000000000000000000000000000000..0d05c83ffe45ee05804556515df1ce330e118152
mode 100644,000000..100644
--- /dev/null
@@@ -1,56 -1,0 +1,73 @@@
- use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::consts::{self, Constant};
-     /// x * -1
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::source::snippet_with_applicability;
 +use if_chain::if_chain;
++use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for multiplication by -1 as a form of negation.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more readable to just negate.
 +    ///
 +    /// ### Known problems
 +    /// This only catches integers (for now).
 +    ///
 +    /// ### Example
 +    /// ```ignore
-     "multiplying integers with `-1`"
++    /// // Bad
++    /// let a = x * -1;
++    ///
++    /// // Good
++    /// let b = -x;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEG_MULTIPLY,
 +    style,
-             span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`");
++    "multiplying integers by `-1`"
 +}
 +
 +declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
 +
 +#[allow(clippy::match_same_arms)]
 +impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref op, left, right) = e.kind {
 +            if BinOpKind::Mul == op.node {
 +                match (&left.kind, &right.kind) {
 +                    (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {},
 +                    (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right),
 +                    (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left),
 +                    _ => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
 +    if_chain! {
 +        if let ExprKind::Lit(ref l) = lit.kind;
 +        if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
 +        if cx.typeck_results().expr_ty(exp).is_integral();
++
 +        then {
++            let mut applicability = Applicability::MachineApplicable;
++            let suggestion = format!("-{}", snippet_with_applicability(cx, exp.span, "..", &mut applicability));
++            span_lint_and_sugg(
++                    cx,
++                    NEG_MULTIPLY,
++                    span,
++                    "this multiplication by -1 can be written more succinctly",
++                    "consider using",
++                    suggestion,
++                    applicability,
++                );
 +        }
 +    }
 +}
index 25fbcb3c6094bb828802221a63e3b8c539654921,0000000000000000000000000000000000000000..39a37e3e378ed4002b483d4b4800250e55e34e48
mode 100644,000000..100644
--- /dev/null
@@@ -1,429 -1,0 +1,429 @@@
-             if allowed_to_be_similar(&interned_name, existing_name.exemptions) {
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 +use rustc_ast::ast::{
 +    self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
 +};
 +use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +use rustc_span::symbol::{Ident, Symbol};
 +use std::cmp::Ordering;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for names that are very similar and thus confusing.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's hard to distinguish between names that differ only
 +    /// by a single character.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// let checked_exp = something;
 +    /// let checked_expr = something_else;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SIMILAR_NAMES,
 +    pedantic,
 +    "similarly named items and bindings"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for too many variables whose name consists of a
 +    /// single character.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's hard to memorize what a variable means without a
 +    /// descriptive name.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// let (a, b, c, d, e, f, g) = (...);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MANY_SINGLE_CHAR_NAMES,
 +    pedantic,
 +    "too many single character bindings"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks if you have variables whose name consists of just
 +    /// underscores and digits.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's hard to memorize what a variable means without a
 +    /// descriptive name.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _1 = 1;
 +    /// let ___1 = 1;
 +    /// let __1___2 = 11;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub JUST_UNDERSCORES_AND_DIGITS,
 +    style,
 +    "unclear name"
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct NonExpressiveNames {
 +    pub single_char_binding_names_threshold: u64,
 +}
 +
 +impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);
 +
 +struct ExistingName {
 +    interned: Symbol,
 +    span: Span,
 +    len: usize,
 +    exemptions: &'static [&'static str],
 +}
 +
 +struct SimilarNamesLocalVisitor<'a, 'tcx> {
 +    names: Vec<ExistingName>,
 +    cx: &'a EarlyContext<'tcx>,
 +    lint: &'a NonExpressiveNames,
 +
 +    /// A stack of scopes containing the single-character bindings in each scope.
 +    single_char_names: Vec<Vec<Ident>>,
 +}
 +
 +impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
 +    fn check_single_char_names(&self) {
 +        let num_single_char_names = self.single_char_names.iter().flatten().count();
 +        let threshold = self.lint.single_char_binding_names_threshold;
 +        if num_single_char_names as u64 > threshold {
 +            let span = self
 +                .single_char_names
 +                .iter()
 +                .flatten()
 +                .map(|ident| ident.span)
 +                .collect::<Vec<_>>();
 +            span_lint(
 +                self.cx,
 +                MANY_SINGLE_CHAR_NAMES,
 +                span,
 +                &format!(
 +                    "{} bindings with single-character names in scope",
 +                    num_single_char_names
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +// this list contains lists of names that are allowed to be similar
 +// the assumption is that no name is ever contained in multiple lists.
 +#[rustfmt::skip]
 +const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[
 +    &["parsed", "parser"],
 +    &["lhs", "rhs"],
 +    &["tx", "rx"],
 +    &["set", "get"],
 +    &["args", "arms"],
 +    &["qpath", "path"],
 +    &["lit", "lint"],
 +    &["wparam", "lparam"],
 +    &["iter", "item"],
 +];
 +
 +struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
 +
 +impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
 +    fn visit_pat(&mut self, pat: &'tcx Pat) {
 +        match pat.kind {
 +            PatKind::Ident(_, ident, _) => {
 +                if !pat.span.from_expansion() {
 +                    self.check_ident(ident);
 +                }
 +            },
 +            PatKind::Struct(_, _, ref fields, _) => {
 +                for field in fields {
 +                    if !field.is_shorthand {
 +                        self.visit_pat(&field.pat);
 +                    }
 +                }
 +            },
 +            // just go through the first pattern, as either all patterns
 +            // bind the same bindings or rustc would have errored much earlier
 +            PatKind::Or(ref pats) => self.visit_pat(&pats[0]),
 +            _ => walk_pat(self, pat),
 +        }
 +    }
 +}
 +
 +#[must_use]
 +fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> {
 +    for &list in ALLOWED_TO_BE_SIMILAR {
 +        if allowed_to_be_similar(interned_name, list) {
 +            return Some(list);
 +        }
 +    }
 +    None
 +}
 +
 +#[must_use]
 +fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool {
 +    list.iter()
 +        .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
 +}
 +
 +impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
 +    fn check_short_ident(&mut self, ident: Ident) {
 +        // Ignore shadowing
 +        if self
 +            .0
 +            .single_char_names
 +            .iter()
 +            .flatten()
 +            .any(|id| id.name == ident.name)
 +        {
 +            return;
 +        }
 +
 +        if let Some(scope) = &mut self.0.single_char_names.last_mut() {
 +            scope.push(ident);
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn check_ident(&mut self, ident: Ident) {
 +        let interned_name = ident.name.as_str();
 +        if interned_name.chars().any(char::is_uppercase) {
 +            return;
 +        }
 +        if interned_name.chars().all(|c| c.is_digit(10) || c == '_') {
 +            span_lint(
 +                self.0.cx,
 +                JUST_UNDERSCORES_AND_DIGITS,
 +                ident.span,
 +                "consider choosing a more descriptive name",
 +            );
 +            return;
 +        }
 +        if interned_name.starts_with('_') {
 +            // these bindings are typically unused or represent an ignored portion of a destructuring pattern
 +            return;
 +        }
 +        let count = interned_name.chars().count();
 +        if count < 3 {
 +            if count == 1 {
 +                self.check_short_ident(ident);
 +            }
 +            return;
 +        }
 +        for existing_name in &self.0.names {
-                         || levenstein_not_1(&interned_name, existing_name.interned.as_str())
++            if allowed_to_be_similar(interned_name, existing_name.exemptions) {
 +                continue;
 +            }
 +            match existing_name.len.cmp(&count) {
 +                Ordering::Greater => {
 +                    if existing_name.len - count != 1
-                         || levenstein_not_1(existing_name.interned.as_str(), &interned_name)
++                        || levenstein_not_1(interned_name, existing_name.interned.as_str())
 +                    {
 +                        continue;
 +                    }
 +                },
 +                Ordering::Less => {
 +                    if count - existing_name.len != 1
-             exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
++                        || levenstein_not_1(existing_name.interned.as_str(), interned_name)
 +                    {
 +                        continue;
 +                    }
 +                },
 +                Ordering::Equal => {
 +                    let mut interned_chars = interned_name.chars();
 +                    let interned_str = existing_name.interned.as_str();
 +                    let mut existing_chars = interned_str.chars();
 +                    let first_i = interned_chars.next().expect("we know we have at least one char");
 +                    let first_e = existing_chars.next().expect("we know we have at least one char");
 +                    let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
 +
 +                    if eq_or_numeric((first_i, first_e)) {
 +                        let last_i = interned_chars.next_back().expect("we know we have at least two chars");
 +                        let last_e = existing_chars.next_back().expect("we know we have at least two chars");
 +                        if eq_or_numeric((last_i, last_e)) {
 +                            if interned_chars
 +                                .zip(existing_chars)
 +                                .filter(|&ie| !eq_or_numeric(ie))
 +                                .count()
 +                                != 1
 +                            {
 +                                continue;
 +                            }
 +                        } else {
 +                            let second_last_i = interned_chars
 +                                .next_back()
 +                                .expect("we know we have at least three chars");
 +                            let second_last_e = existing_chars
 +                                .next_back()
 +                                .expect("we know we have at least three chars");
 +                            if !eq_or_numeric((second_last_i, second_last_e))
 +                                || second_last_i == '_'
 +                                || !interned_chars.zip(existing_chars).all(eq_or_numeric)
 +                            {
 +                                // allowed similarity foo_x, foo_y
 +                                // or too many chars differ (foo_x, boo_y) or (foox, booy)
 +                                continue;
 +                            }
 +                        }
 +                    } else {
 +                        let second_i = interned_chars.next().expect("we know we have at least two chars");
 +                        let second_e = existing_chars.next().expect("we know we have at least two chars");
 +                        if !eq_or_numeric((second_i, second_e))
 +                            || second_i == '_'
 +                            || !interned_chars.zip(existing_chars).all(eq_or_numeric)
 +                        {
 +                            // allowed similarity x_foo, y_foo
 +                            // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
 +                            continue;
 +                        }
 +                    }
 +                },
 +            }
 +            span_lint_and_then(
 +                self.0.cx,
 +                SIMILAR_NAMES,
 +                ident.span,
 +                "binding's name is too similar to existing binding",
 +                |diag| {
 +                    diag.span_note(existing_name.span, "existing binding defined here");
 +                },
 +            );
 +            return;
 +        }
 +        self.0.names.push(ExistingName {
++            exemptions: get_exemptions(interned_name).unwrap_or(&[]),
 +            interned: ident.name,
 +            span: ident.span,
 +            len: count,
 +        });
 +    }
 +}
 +
 +impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
 +    /// ensure scoping rules work
 +    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
 +        let n = self.names.len();
 +        let single_char_count = self.single_char_names.len();
 +        f(self);
 +        self.names.truncate(n);
 +        self.single_char_names.truncate(single_char_count);
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
 +    fn visit_local(&mut self, local: &'tcx Local) {
 +        if let Some((init, els)) = &local.kind.init_else_opt() {
 +            self.apply(|this| walk_expr(this, init));
 +            if let Some(els) = els {
 +                self.apply(|this| walk_block(this, els));
 +            }
 +        }
 +        // add the pattern after the expression because the bindings aren't available
 +        // yet in the init
 +        // expression
 +        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
 +    }
 +    fn visit_block(&mut self, blk: &'tcx Block) {
 +        self.single_char_names.push(vec![]);
 +
 +        self.apply(|this| walk_block(this, blk));
 +
 +        self.check_single_char_names();
 +        self.single_char_names.pop();
 +    }
 +    fn visit_arm(&mut self, arm: &'tcx Arm) {
 +        self.single_char_names.push(vec![]);
 +
 +        self.apply(|this| {
 +            SimilarNamesNameVisitor(this).visit_pat(&arm.pat);
 +            this.apply(|this| walk_expr(this, &arm.body));
 +        });
 +
 +        self.check_single_char_names();
 +        self.single_char_names.pop();
 +    }
 +    fn visit_item(&mut self, _: &Item) {
 +        // do not recurse into inner items
 +    }
 +}
 +
 +impl EarlyLintPass for NonExpressiveNames {
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 +        if in_external_macro(cx.sess, item.span) {
 +            return;
 +        }
 +
 +        if let ItemKind::Fn(box ast::Fn {
 +            ref sig,
 +            body: Some(ref blk),
 +            ..
 +        }) = item.kind
 +        {
 +            do_check(self, cx, &item.attrs, &sig.decl, blk);
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
 +        if in_external_macro(cx.sess, item.span) {
 +            return;
 +        }
 +
 +        if let AssocItemKind::Fn(box ast::Fn {
 +            ref sig,
 +            body: Some(ref blk),
 +            ..
 +        }) = item.kind
 +        {
 +            do_check(self, cx, &item.attrs, &sig.decl, blk);
 +        }
 +    }
 +}
 +
 +fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
 +    if !attrs.iter().any(|attr| attr.has_name(sym::test)) {
 +        let mut visitor = SimilarNamesLocalVisitor {
 +            names: Vec::new(),
 +            cx,
 +            lint,
 +            single_char_names: vec![vec![]],
 +        };
 +
 +        // initialize with function arguments
 +        for arg in &decl.inputs {
 +            SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
 +        }
 +        // walk all other bindings
 +        walk_block(&mut visitor, blk);
 +
 +        visitor.check_single_char_names();
 +    }
 +}
 +
 +/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
 +#[must_use]
 +fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
 +    debug_assert!(a_name.chars().count() < b_name.chars().count());
 +    let mut a_chars = a_name.chars();
 +    let mut b_chars = b_name.chars();
 +    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
 +        if a == b {
 +            continue;
 +        }
 +        if let Some(b2) = b_chars.next() {
 +            // check if there's just one character inserted
 +            return a != b2 || a_chars.ne(b_chars);
 +        }
 +        // tuple
 +        // ntuple
 +        return true;
 +    }
 +    // for item in items
 +    true
 +}
index 52c060bc42c7ab7dba51ee740aa1fcaaacdbc7cf,0000000000000000000000000000000000000000..c8cbfefb63d65059b3b65c4d0ff6e875e97e334c
mode 100644,000000..100644
--- /dev/null
@@@ -1,544 -1,0 +1,544 @@@
-                     let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
-                     let end = Sugg::hir(cx, y, "y");
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path};
 +use clippy_utils::{higher, SpanlessEq};
 +use if_chain::if_chain;
 +use rustc_ast::ast::RangeLimits;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::ty;
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::sym;
 +use rustc_span::symbol::Ident;
 +use std::cmp::Ordering;
 +
 +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];
 +    /// x.iter().zip(0..x.len());
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let x = vec![1];
 +    /// 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 exclusive ranges where 1 is added to the
 +    /// upper bound, e.g., `x..(y+1)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The code is more readable with an inclusive range
 +    /// like `x..=y`.
 +    ///
 +    /// ### Known problems
 +    /// Will add unnecessary pair of parentheses when the
 +    /// expression is not wrapped in a pair but starts with an opening parenthesis
 +    /// and ends with a closing one.
 +    /// I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
 +    ///
 +    /// Also in many cases, inclusive ranges are still slower to run than
 +    /// exclusive ranges, because they essentially add an extra branch that
 +    /// LLVM may fail to hoist out of the loop.
 +    ///
 +    /// This will cause a warning that cannot be fixed if the consumer of the
 +    /// range only accepts a specific range type, instead of the generic
 +    /// `RangeBounds` trait
 +    /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// for x..(y+1) { .. }
 +    /// ```
 +    /// Could be written as
 +    /// ```rust,ignore
 +    /// for x..=y { .. }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub RANGE_PLUS_ONE,
 +    pedantic,
 +    "`x..(y+1)` reads better as `x..=y`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for inclusive ranges where 1 is subtracted from
 +    /// the upper bound, e.g., `x..=(y-1)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The code is more readable with an exclusive range
 +    /// like `x..y`.
 +    ///
 +    /// ### Known problems
 +    /// This will cause a warning that cannot be fixed if
 +    /// the consumer of the range only accepts a specific range type, instead of
 +    /// the generic `RangeBounds` trait
 +    /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// for x..=(y-1) { .. }
 +    /// ```
 +    /// Could be written as
 +    /// ```rust,ignore
 +    /// for x..y { .. }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub RANGE_MINUS_ONE,
 +    pedantic,
 +    "`x..=(y-1)` reads better as `x..y`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for range expressions `x..y` where both `x` and `y`
 +    /// are constant and `x` is greater or equal to `y`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Empty ranges yield no values so iterating them is a no-op.
 +    /// Moreover, trying to use a reversed range to index a slice will panic at run-time.
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// fn main() {
 +    ///     (10..=0).for_each(|x| println!("{}", x));
 +    ///
 +    ///     let arr = [1, 2, 3, 4, 5];
 +    ///     let sub = &arr[3..1];
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn main() {
 +    ///     (0..=10).rev().for_each(|x| println!("{}", x));
 +    ///
 +    ///     let arr = [1, 2, 3, 4, 5];
 +    ///     let sub = &arr[1..3];
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub REVERSED_EMPTY_RANGES,
 +    correctness,
 +    "reversing the limits of range expressions, resulting in empty ranges"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions like `x >= 3 && x < 8` that could
 +    /// be more readably expressed as `(3..8).contains(x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `contains` expresses the intent better and has less
 +    /// failure modes (such as fencepost errors or using `||` instead of `&&`).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // given
 +    /// let x = 6;
 +    ///
 +    /// assert!(x >= 3 && x < 8);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    ///# let x = 6;
 +    /// assert!((3..8).contains(&x));
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub MANUAL_RANGE_CONTAINS,
 +    style,
 +    "manually reimplementing {`Range`, `RangeInclusive`}`::contains`"
 +}
 +
 +pub struct Ranges {
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl Ranges {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(Ranges => [
 +    RANGE_ZIP_WITH_LEN,
 +    RANGE_PLUS_ONE,
 +    RANGE_MINUS_ONE,
 +    REVERSED_EMPTY_RANGES,
 +    MANUAL_RANGE_CONTAINS,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Ranges {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        match expr.kind {
 +            ExprKind::MethodCall(path, _, args, _) => {
 +                check_range_zip_with_len(cx, path, args, expr.span);
 +            },
 +            ExprKind::Binary(ref op, l, r) => {
 +                if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) {
 +                    check_possible_range_contains(cx, op.node, l, r, expr);
 +                }
 +            },
 +            _ => {},
 +        }
 +
 +        check_exclusive_range_plus_one(cx, expr);
 +        check_inclusive_range_minus_one(cx, expr);
 +        check_reversed_empty_range(cx, expr);
 +    }
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, expr: &Expr<'_>) {
 +    if in_constant(cx, expr.hir_id) {
 +        return;
 +    }
 +
 +    let span = expr.span;
 +    let combine_and = match op {
 +        BinOpKind::And | BinOpKind::BitAnd => true,
 +        BinOpKind::Or | BinOpKind::BitOr => false,
 +        _ => return,
 +    };
 +    // value, name, order (higher/lower), inclusiveness
 +    if let (Some((lval, lname, name_span, lval_span, lord, linc)), Some((rval, rname, _, rval_span, rord, rinc))) =
 +        (check_range_bounds(cx, l), check_range_bounds(cx, r))
 +    {
 +        // we only lint comparisons on the same name and with different
 +        // direction
 +        if lname != rname || lord == rord {
 +            return;
 +        }
 +        let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
 +        if combine_and && ord == Some(rord) {
 +            // order lower bound and upper bound
 +            let (l_span, u_span, l_inc, u_inc) = if rord == Ordering::Less {
 +                (lval_span, rval_span, linc, rinc)
 +            } else {
 +                (rval_span, lval_span, rinc, linc)
 +            };
 +            // we only lint inclusive lower bounds
 +            if !l_inc {
 +                return;
 +            }
 +            let (range_type, range_op) = if u_inc {
 +                ("RangeInclusive", "..=")
 +            } else {
 +                ("Range", "..")
 +            };
 +            let mut applicability = Applicability::MachineApplicable;
 +            let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
 +            let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
 +            let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
 +            let space = if lo.ends_with('.') { " " } else { "" };
 +            span_lint_and_sugg(
 +                cx,
 +                MANUAL_RANGE_CONTAINS,
 +                span,
 +                &format!("manual `{}::contains` implementation", range_type),
 +                "use",
 +                format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
 +                applicability,
 +            );
 +        } else if !combine_and && ord == Some(lord) {
 +            // `!_.contains(_)`
 +            // order lower bound and upper bound
 +            let (l_span, u_span, l_inc, u_inc) = if lord == Ordering::Less {
 +                (lval_span, rval_span, linc, rinc)
 +            } else {
 +                (rval_span, lval_span, rinc, linc)
 +            };
 +            if l_inc {
 +                return;
 +            }
 +            let (range_type, range_op) = if u_inc {
 +                ("Range", "..")
 +            } else {
 +                ("RangeInclusive", "..=")
 +            };
 +            let mut applicability = Applicability::MachineApplicable;
 +            let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
 +            let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
 +            let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
 +            let space = if lo.ends_with('.') { " " } else { "" };
 +            span_lint_and_sugg(
 +                cx,
 +                MANUAL_RANGE_CONTAINS,
 +                span,
 +                &format!("manual `!{}::contains` implementation", range_type),
 +                "use",
 +                format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> {
 +    if let ExprKind::Binary(ref op, l, r) = ex.kind {
 +        let (inclusive, ordering) = match op.node {
 +            BinOpKind::Gt => (false, Ordering::Greater),
 +            BinOpKind::Ge => (true, Ordering::Greater),
 +            BinOpKind::Lt => (false, Ordering::Less),
 +            BinOpKind::Le => (true, Ordering::Less),
 +            _ => return None,
 +        };
 +        if let Some(id) = match_ident(l) {
 +            if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
 +                return Some((c, id, l.span, r.span, ordering, inclusive));
 +            }
 +        } else if let Some(id) = match_ident(r) {
 +            if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
 +                return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
 +            }
 +        }
 +    }
 +    None
 +}
 +
 +fn match_ident(e: &Expr<'_>) -> Option<Ident> {
 +    if let ExprKind::Path(ref qpath) = e.kind {
 +        if let Some(seg) = single_segment_path(qpath) {
 +            if seg.args.is_none() {
 +                return Some(seg.ident);
 +            }
 +        }
 +    }
 +    None
 +}
 +
 +fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
 +    if_chain! {
 +        if path.ident.as_str() == "zip";
 +        if let [iter, zip_arg] = args;
 +        // `.iter()` call
 +        if let ExprKind::MethodCall(iter_path, _, iter_args, _) = iter.kind;
 +        if iter_path.ident.name == sym::iter;
 +        // range expression in `.zip()` call: `0..x.len()`
 +        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
 +        if is_integer_const(cx, start, 0);
 +        // `.len()` call
 +        if let ExprKind::MethodCall(len_path, _, len_args, _) = end.kind;
 +        if len_path.ident.name == sym::len && len_args.len() == 1;
 +        // `.iter()` and `.len()` called on same `Path`
 +        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
 +        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
 +        if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
 +        then {
 +            span_lint(cx,
 +                RANGE_ZIP_WITH_LEN,
 +                span,
 +                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
 +                    snippet(cx, iter_args[0].span, "_"))
 +            );
 +        }
 +    }
 +}
 +
 +// exclusive range plus one: `x..(y+1)`
 +fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if_chain! {
 +        if let Some(higher::Range {
 +            start,
 +            end: Some(end),
 +            limits: RangeLimits::HalfOpen
 +        }) = higher::Range::hir(expr);
 +        if let Some(y) = y_plus_one(cx, end);
 +        then {
 +            let span = if expr.span.from_expansion() {
 +                expr.span
 +                    .ctxt()
 +                    .outer_expn_data()
 +                    .call_site
 +            } else {
 +                expr.span
 +            };
 +            span_lint_and_then(
 +                cx,
 +                RANGE_PLUS_ONE,
 +                span,
 +                "an inclusive range would be more readable",
 +                |diag| {
-                     let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
-                     let end = Sugg::hir(cx, y, "y");
++                    let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
++                    let end = Sugg::hir(cx, y, "y").maybe_par();
 +                    if let Some(is_wrapped) = &snippet_opt(cx, span) {
 +                        if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
 +                            diag.span_suggestion(
 +                                span,
 +                                "use",
 +                                format!("({}..={})", start, end),
 +                                Applicability::MaybeIncorrect,
 +                            );
 +                        } else {
 +                            diag.span_suggestion(
 +                                span,
 +                                "use",
 +                                format!("{}..={}", start, end),
 +                                Applicability::MachineApplicable, // snippet
 +                            );
 +                        }
 +                    }
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +// inclusive range minus one: `x..=(y-1)`
 +fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if_chain! {
 +        if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
 +        if let Some(y) = y_minus_one(cx, end);
 +        then {
 +            span_lint_and_then(
 +                cx,
 +                RANGE_MINUS_ONE,
 +                expr.span,
 +                "an exclusive range would be more readable",
 +                |diag| {
++                    let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
++                    let end = Sugg::hir(cx, y, "y").maybe_par();
 +                    diag.span_suggestion(
 +                        expr.span,
 +                        "use",
 +                        format!("{}..{}", start, end),
 +                        Applicability::MachineApplicable, // snippet
 +                    );
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    fn inside_indexing_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +        matches!(
 +            get_parent_expr(cx, expr),
 +            Some(Expr {
 +                kind: ExprKind::Index(..),
 +                ..
 +            })
 +        )
 +    }
 +
 +    fn is_for_loop_arg(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +        let mut cur_expr = expr;
 +        while let Some(parent_expr) = get_parent_expr(cx, cur_expr) {
 +            match higher::ForLoop::hir(parent_expr) {
 +                Some(higher::ForLoop { arg, .. }) if arg.hir_id == expr.hir_id => return true,
 +                _ => cur_expr = parent_expr,
 +            }
 +        }
 +
 +        false
 +    }
 +
 +    fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
 +        match limits {
 +            RangeLimits::HalfOpen => ordering != Ordering::Less,
 +            RangeLimits::Closed => ordering == Ordering::Greater,
 +        }
 +    }
 +
 +    if_chain! {
 +        if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr);
 +        let ty = cx.typeck_results().expr_ty(start);
 +        if let ty::Int(_) | ty::Uint(_) = ty.kind();
 +        if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
 +        if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end);
 +        if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
 +        if is_empty_range(limits, ordering);
 +        then {
 +            if inside_indexing_expr(cx, expr) {
 +                // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ...
 +                if ordering != Ordering::Equal {
 +                    span_lint(
 +                        cx,
 +                        REVERSED_EMPTY_RANGES,
 +                        expr.span,
 +                        "this range is reversed and using it to index a slice will panic at run-time",
 +                    );
 +                }
 +            // ... except in for loop arguments for backwards compatibility with `reverse_range_loop`
 +            } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) {
 +                span_lint_and_then(
 +                    cx,
 +                    REVERSED_EMPTY_RANGES,
 +                    expr.span,
 +                    "this range is empty so it will yield no values",
 +                    |diag| {
 +                        if ordering != Ordering::Equal {
 +                            let start_snippet = snippet(cx, start.span, "_");
 +                            let end_snippet = snippet(cx, end.span, "_");
 +                            let dots = match limits {
 +                                RangeLimits::HalfOpen => "..",
 +                                RangeLimits::Closed => "..="
 +                            };
 +
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "consider using the following if you are attempting to iterate over this \
 +                                 range in reverse",
 +                                format!("({}{}{}).rev()", end_snippet, dots, start_snippet),
 +                                Applicability::MaybeIncorrect,
 +                            );
 +                        }
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn y_plus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> {
 +    match expr.kind {
 +        ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Add, ..
 +            },
 +            lhs,
 +            rhs,
 +        ) => {
 +            if is_integer_const(cx, lhs, 1) {
 +                Some(rhs)
 +            } else if is_integer_const(cx, rhs, 1) {
 +                Some(lhs)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn y_minus_one<'t>(cx: &LateContext<'_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> {
 +    match expr.kind {
 +        ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Sub, ..
 +            },
 +            lhs,
 +            rhs,
 +        ) if is_integer_const(cx, rhs, 1) => Some(lhs),
 +        _ => None,
 +    }
 +}
index 1118da6c8cb57299cff3acb51bf8c2d0940a5367,0000000000000000000000000000000000000000..b57ec96bc7e6d101a41d53aa1622bca70cd473cf
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,108 @@@
- use clippy_utils::{diagnostics::span_lint, must_use_attr, nth_arg, return_ty};
++use clippy_utils::ty::is_must_use_ty;
++use clippy_utils::{diagnostics::span_lint, nth_arg, return_ty};
 +use rustc_hir::def_id::LocalDefId;
 +use rustc_hir::intravisit::FnKind;
 +use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
 +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::Span;
++use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
 +    ///
 +    /// ### Why is this bad?
 +    /// It prevents to "forget" to use the newly created value.
 +    ///
 +    /// ### Limitations
 +    /// This lint is only applied on methods taking a `self` argument. It would be mostly noise
 +    /// if it was added on constructors for example.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// pub struct Bar;
 +    ///
 +    /// impl Bar {
 +    ///     // Bad
 +    ///     pub fn bar(&self) -> Self {
 +    ///         Self
 +    ///     }
 +    ///
 +    ///     // Good
 +    ///     #[must_use]
 +    ///     pub fn foo(&self) -> Self {
 +    ///         Self
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.59.0"]
 +    pub RETURN_SELF_NOT_MUST_USE,
 +    suspicious,
 +    "missing `#[must_use]` annotation on a method returning `Self`"
 +}
 +
 +declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 +
 +fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
 +    if_chain! {
 +        // If it comes from an external macro, better ignore it.
 +        if !in_external_macro(cx.sess(), span);
 +        if decl.implicit_self.has_implicit_self();
 +        // We only show this warning for public exported methods.
 +        if cx.access_levels.is_exported(fn_def);
++        // We don't want to emit this lint if the `#[must_use]` attribute is already there.
++        if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
 +        if cx.tcx.visibility(fn_def.to_def_id()).is_public();
-         // No need to warn if the attribute is already present.
-         if must_use_attr(cx.tcx.hir().attrs(hir_id)).is_none();
 +        let ret_ty = return_ty(cx, hir_id);
 +        let self_arg = nth_arg(cx, hir_id, 0);
 +        // If `Self` has the same type as the returned type, then we want to warn.
 +        //
 +        // For this check, we don't want to remove the reference on the returned type because if
 +        // there is one, we shouldn't emit a warning!
 +        if self_arg.peel_refs() == ret_ty;
++        // If `Self` is already marked as `#[must_use]`, no need for the attribute here.
++        if !is_must_use_ty(cx, ret_ty);
 +
 +        then {
 +            span_lint(
 +                cx,
 +                RETURN_SELF_NOT_MUST_USE,
 +                span,
 +                "missing `#[must_use]` attribute on a method returning `Self`",
 +            );
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        kind: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'tcx>,
 +        _: &'tcx Body<'tcx>,
 +        span: Span,
 +        hir_id: HirId,
 +    ) {
 +        if_chain! {
 +            // We are only interested in methods, not in functions or associated functions.
 +            if matches!(kind, FnKind::Method(_, _, _));
 +            if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
 +            if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
 +            // We don't want this method to be te implementation of a trait because the
 +            // `#[must_use]` should be put on the trait definition directly.
 +            if cx.tcx.trait_id_of_impl(impl_def).is_none();
 +
 +            then {
 +                check_method(cx, decl, fn_def, span, hir_id);
 +            }
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
 +        if let TraitItemKind::Fn(ref sig, _) = item.kind {
 +            check_method(cx, sig.decl, item.def_id, item.span, item.hir_id());
 +        }
 +    }
 +}
index 494bc7dda18e76008aebf3460fb1d64b4a88d0ee,0000000000000000000000000000000000000000..112ccdcdd4202af8fdfea61895e67a38fddfebf6
mode 100644,000000..100644
--- /dev/null
@@@ -1,302 -1,0 +1,314 @@@
-                 check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Block);
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet_opt;
 +use clippy_utils::{fn_def_id, path_to_local_id};
 +use if_chain::if_chain;
 +use rustc_ast::ast::Attribute;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::subst::GenericArgKind;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::hygiene::DesugaringKind;
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `let`-bindings, which are subsequently
 +    /// returned.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is just extraneous code. Remove it to make your code
 +    /// more rusty.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn foo() -> String {
 +    ///     let x = String::new();
 +    ///     x
 +    /// }
 +    /// ```
 +    /// instead, use
 +    /// ```
 +    /// fn foo() -> String {
 +    ///     String::new()
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub LET_AND_RETURN,
 +    style,
 +    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for return statements at the end of a block.
 +    ///
 +    /// ### Why is this bad?
 +    /// Removing the `return` and semicolon will make the code
 +    /// more rusty.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn foo(x: usize) -> usize {
 +    ///     return x;
 +    /// }
 +    /// ```
 +    /// simplify to
 +    /// ```rust
 +    /// fn foo(x: usize) -> usize {
 +    ///     x
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEEDLESS_RETURN,
 +    style,
 +    "using a return statement like `return expr;` where an expression would suffice"
 +}
 +
 +#[derive(PartialEq, Eq, Copy, Clone)]
 +enum RetReplacement {
 +    Empty,
 +    Block,
++    Unit,
 +}
 +
 +declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Return {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
 +        // we need both a let-binding stmt and an expr
 +        if_chain! {
 +            if let Some(retexpr) = block.expr;
 +            if let Some(stmt) = block.stmts.iter().last();
 +            if let StmtKind::Local(local) = &stmt.kind;
 +            if local.ty.is_none();
 +            if cx.tcx.hir().attrs(local.hir_id).is_empty();
 +            if let Some(initexpr) = &local.init;
 +            if let PatKind::Binding(_, local_id, _, _) = local.pat.kind;
 +            if path_to_local_id(retexpr, local_id);
 +            if !last_statement_borrows(cx, initexpr);
 +            if !in_external_macro(cx.sess(), initexpr.span);
 +            if !in_external_macro(cx.sess(), retexpr.span);
 +            if !local.span.from_expansion();
 +            then {
 +                span_lint_and_then(
 +                    cx,
 +                    LET_AND_RETURN,
 +                    retexpr.span,
 +                    "returning the result of a `let` binding from a block",
 +                    |err| {
 +                        err.span_label(local.span, "unnecessary `let` binding");
 +
 +                        if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
 +                            if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
 +                                snippet.push_str(" as _");
 +                            }
 +                            err.multipart_suggestion(
 +                                "return the expression directly",
 +                                vec![
 +                                    (local.span, String::new()),
 +                                    (retexpr.span, snippet),
 +                                ],
 +                                Applicability::MachineApplicable,
 +                            );
 +                        } else {
 +                            err.span_help(initexpr.span, "this expression can be directly returned");
 +                        }
 +                    },
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        kind: FnKind<'tcx>,
 +        _: &'tcx FnDecl<'tcx>,
 +        body: &'tcx Body<'tcx>,
 +        _: Span,
 +        _: HirId,
 +    ) {
 +        match kind {
 +            FnKind::Closure => {
 +                // when returning without value in closure, replace this `return`
 +                // with an empty block to prevent invalid suggestion (see #6501)
 +                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
 +                    RetReplacement::Block
 +                } else {
 +                    RetReplacement::Empty
 +                };
 +                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
 +            },
 +            FnKind::ItemFn(..) | FnKind::Method(..) => {
 +                if let ExprKind::Block(block, _) = body.value.kind {
 +                    check_block_return(cx, block);
 +                }
 +            },
 +        }
 +    }
 +}
 +
 +fn attr_is_cfg(attr: &Attribute) -> bool {
 +    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
 +}
 +
 +fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
 +    if let Some(expr) = block.expr {
 +        check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
 +    } else if let Some(stmt) = block.stmts.iter().last() {
 +        match stmt.kind {
 +            StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
 +                check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
 +            },
 +            _ => (),
 +        }
 +    }
 +}
 +
 +fn check_final_expr<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'tcx>,
 +    span: Option<Span>,
 +    replacement: RetReplacement,
 +) {
 +    match expr.kind {
 +        // simple return is always "bad"
 +        ExprKind::Ret(ref inner) => {
 +            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
 +            let attrs = cx.tcx.hir().attrs(expr.hir_id);
 +            if !attrs.iter().any(attr_is_cfg) {
 +                let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
 +                if !borrows {
 +                    emit_return_lint(
 +                        cx,
 +                        span.expect("`else return` is not possible"),
 +                        inner.as_ref().map(|i| i.span),
 +                        replacement,
 +                    );
 +                }
 +            }
 +        },
 +        // a whole block? check it!
 +        ExprKind::Block(block, _) => {
 +            check_block_return(cx, block);
 +        },
 +        ExprKind::If(_, then, else_clause_opt) => {
 +            if let ExprKind::Block(ifblock, _) = then.kind {
 +                check_block_return(cx, ifblock);
 +            }
 +            if let Some(else_clause) = else_clause_opt {
 +                if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) {
 +                    check_final_expr(cx, else_clause, None, RetReplacement::Empty);
 +                }
 +            }
 +        },
 +        // a match expr, check all arms
 +        // an if/if let expr, check both exprs
 +        // note, if without else is going to be a type checking error anyways
 +        // (except for unit type functions) so we don't match it
 +        ExprKind::Match(_, arms, MatchSource::Normal) => {
 +            for arm in arms.iter() {
++                check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Unit);
 +            }
 +        },
 +        ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty),
 +        _ => (),
 +    }
 +}
 +
 +fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
 +    if ret_span.from_expansion() {
 +        return;
 +    }
 +    match inner_span {
 +        Some(inner_span) => {
 +            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
 +                return;
 +            }
 +
 +            span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
 +                if let Some(snippet) = snippet_opt(cx, inner_span) {
 +                    diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
 +                }
 +            });
 +        },
 +        None => match replacement {
 +            RetReplacement::Empty => {
 +                span_lint_and_sugg(
 +                    cx,
 +                    NEEDLESS_RETURN,
 +                    ret_span,
 +                    "unneeded `return` statement",
 +                    "remove `return`",
 +                    String::new(),
 +                    Applicability::MachineApplicable,
 +                );
 +            },
 +            RetReplacement::Block => {
 +                span_lint_and_sugg(
 +                    cx,
 +                    NEEDLESS_RETURN,
 +                    ret_span,
 +                    "unneeded `return` statement",
 +                    "replace `return` with an empty block",
 +                    "{}".to_string(),
 +                    Applicability::MachineApplicable,
 +                );
++            },
++            RetReplacement::Unit => {
++                span_lint_and_sugg(
++                    cx,
++                    NEEDLESS_RETURN,
++                    ret_span,
++                    "unneeded `return` statement",
++                    "replace `return` with a unit value",
++                    "()".to_string(),
++                    Applicability::MachineApplicable,
++                );
 +            },
 +        },
 +    }
 +}
 +
 +fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
 +    let mut visitor = BorrowVisitor { cx, borrows: false };
 +    walk_expr(&mut visitor, expr);
 +    visitor.borrows
 +}
 +
 +struct BorrowVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    borrows: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.borrows {
 +            return;
 +        }
 +
 +        if let Some(def_id) = fn_def_id(self.cx, expr) {
 +            self.borrows = self
 +                .cx
 +                .tcx
 +                .fn_sig(def_id)
 +                .output()
 +                .skip_binder()
 +                .walk(self.cx.tcx)
 +                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index f6880af0cab28a068709a113ab03b81479db97c3,0000000000000000000000000000000000000000..ce05c5a6164fd76ab6e88bf137de1fcb7bc0663e
mode 100644,000000..100644
--- /dev/null
@@@ -1,239 -1,0 +1,239 @@@
- use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp};
 +use clippy_utils::diagnostics::span_lint_and_note;
 +use clippy_utils::source::snippet;
 +use clippy_utils::visitors::is_local_used;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir::def::Res;
 +use rustc_hir::def_id::LocalDefId;
 +use rustc_hir::hir_id::ItemLocalId;
- /// Finds the "init" expression for a pattern: `let <pat> = <init>;` or
++use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{Span, Symbol};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, while just changing reference level or mutability.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not much, in fact it's a very common pattern in Rust
 +    /// code. Still, some may opt to avoid it in their code base, they can set this
 +    /// lint to `Warn`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// // Bad
 +    /// let x = &x;
 +    ///
 +    /// // Good
 +    /// let y = &x; // use different variable name
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHADOW_SAME,
 +    restriction,
 +    "rebinding a name to itself, e.g., `let mut x = &mut x`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, while reusing the original value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not too much, in fact it's a common pattern in Rust
 +    /// code. Still, some argue that name shadowing like this hurts readability,
 +    /// because a value may be bound to different things depending on position in
 +    /// the code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 2;
 +    /// let x = x + 1;
 +    /// ```
 +    /// use different variable name:
 +    /// ```rust
 +    /// let x = 2;
 +    /// let y = x + 1;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHADOW_REUSE,
 +    restriction,
 +    "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, either without an initialization or with one that does not even use
 +    /// the original value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Name shadowing can hurt readability, especially in
 +    /// large code bases, because it is easy to lose track of the active binding at
 +    /// any place in the code. This can be alleviated by either giving more specific
 +    /// names to bindings or introducing more scopes to contain the bindings.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let y = 1;
 +    /// # let z = 2;
 +    /// let x = y;
 +    ///
 +    /// // Bad
 +    /// let x = z; // shadows the earlier binding
 +    ///
 +    /// // Good
 +    /// let w = z; // use different variable name
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHADOW_UNRELATED,
 +    restriction,
 +    "rebinding a name without even using the original value"
 +}
 +
 +#[derive(Default)]
 +pub(crate) struct Shadow {
 +    bindings: Vec<FxHashMap<Symbol, Vec<ItemLocalId>>>,
 +}
 +
 +impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Shadow {
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        let (id, ident) = match pat.kind {
 +            PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
 +            _ => return,
 +        };
 +
 +        if pat.span.desugaring_kind().is_some() {
 +            return;
 +        }
 +
 +        if ident.span.from_expansion() || ident.span.is_dummy() {
 +            return;
 +        }
 +
 +        let HirId { owner, local_id } = id;
 +        // get (or insert) the list of items for this owner and symbol
 +        let data = self.bindings.last_mut().unwrap();
 +        let items_with_name = data.entry(ident.name).or_default();
 +
 +        // check other bindings with the same name, most recently seen first
 +        for &prev in items_with_name.iter().rev() {
 +            if prev == local_id {
 +                // repeated binding in an `Or` pattern
 +                return;
 +            }
 +
 +            if is_shadow(cx, owner, prev, local_id) {
 +                let prev_hir_id = HirId { owner, local_id: prev };
 +                lint_shadow(cx, pat, prev_hir_id, ident.span);
 +                // only lint against the "nearest" shadowed binding
 +                break;
 +            }
 +        }
 +        // store the binding
 +        items_with_name.push(local_id);
 +    }
 +
 +    fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
 +        let hir = cx.tcx.hir();
 +        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
 +            self.bindings.push(FxHashMap::default());
 +        }
 +    }
 +
 +    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
 +        let hir = cx.tcx.hir();
 +        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
 +            self.bindings.pop();
 +        }
 +    }
 +}
 +
 +fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
 +    let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
 +    let first_scope = scope_tree.var_scope(first);
 +    let second_scope = scope_tree.var_scope(second);
 +    scope_tree.is_subscope_of(second_scope, first_scope)
 +}
 +
 +fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) {
 +    let (lint, msg) = match find_init(cx, pat.hir_id) {
 +        Some(expr) if is_self_shadow(cx, pat, expr, shadowed) => {
 +            let msg = format!(
 +                "`{}` is shadowed by itself in `{}`",
 +                snippet(cx, pat.span, "_"),
 +                snippet(cx, expr.span, "..")
 +            );
 +            (SHADOW_SAME, msg)
 +        },
 +        Some(expr) if is_local_used(cx, expr, shadowed) => {
 +            let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
 +            (SHADOW_REUSE, msg)
 +        },
 +        _ => {
 +            let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
 +            (SHADOW_UNRELATED, msg)
 +        },
 +    };
 +    span_lint_and_note(
 +        cx,
 +        lint,
 +        span,
 +        &msg,
 +        Some(cx.tcx.hir().span(shadowed)),
 +        "previous binding is here",
 +    );
 +}
 +
 +/// Returns true if the expression is a simple transformation of a local binding such as `&x`
 +fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_id: HirId) -> bool {
 +    let hir = cx.tcx.hir();
 +    let is_direct_binding = hir
 +        .parent_iter(pat.hir_id)
 +        .map_while(|(_id, node)| match node {
 +            Node::Pat(pat) => Some(pat),
 +            _ => None,
 +        })
 +        .all(|pat| matches!(pat.kind, PatKind::Ref(..) | PatKind::Or(_)));
 +    if !is_direct_binding {
 +        return false;
 +    }
 +    loop {
 +        expr = match expr.kind {
 +            ExprKind::Box(e)
 +            | ExprKind::AddrOf(_, _, e)
 +            | ExprKind::Block(
 +                &Block {
 +                    stmts: [],
 +                    expr: Some(e),
 +                    ..
 +                },
 +                _,
 +            )
 +            | ExprKind::Unary(UnOp::Deref, e) => e,
 +            ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
 +            _ => break false,
 +        }
 +    }
 +}
 +
-                 ExprKind::Match(e, _, _) => Some(e),
++/// Finds the "init" expression for a pattern: `let <pat> = <init>;` (or `if let`) or
 +/// `match <init> { .., <pat> => .., .. }`
 +fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in cx.tcx.hir().parent_iter(hir_id) {
 +        let init = match node {
 +            Node::Arm(_) | Node::Pat(_) => continue,
 +            Node::Expr(expr) => match expr.kind {
++                ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e),
 +                _ => None,
 +            },
 +            Node::Local(local) => local.init,
 +            _ => None,
 +        };
 +        return init;
 +    }
 +    None
 +}
index c9b4b245f4cc25019d130f05b33151bf80a81bdf,0000000000000000000000000000000000000000..15543b6a2627785bd303a948f911b1fb5bbe1cc1
mode 100644,000000..100644
--- /dev/null
@@@ -1,231 -1,0 +1,231 @@@
-             for (lo, hi) in get_chunks_of_tabs(&comment) {
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use rustc_ast::ast;
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::{BytePos, Span};
 +use std::convert::TryFrom;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks doc comments for usage of tab characters.
 +    ///
 +    /// ### Why is this bad?
 +    /// The rust style-guide promotes spaces instead of tabs for indentation.
 +    /// To keep a consistent view on the source, also doc comments should not have tabs.
 +    /// Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the
 +    /// display settings of the author and reader differ.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// ///
 +    /// /// Struct to hold two strings:
 +    /// ///   - first         one
 +    /// ///   - second        one
 +    /// pub struct DoubleString {
 +    ///    ///
 +    ///    ///        - First String:
 +    ///    ///                - needs to be inside here
 +    ///    first_string: String,
 +    ///    ///
 +    ///    ///        - Second String:
 +    ///    ///                - needs to be inside here
 +    ///    second_string: String,
 +    ///}
 +    /// ```
 +    ///
 +    /// Will be converted to:
 +    /// ```rust
 +    /// ///
 +    /// /// Struct to hold two strings:
 +    /// ///     - first        one
 +    /// ///     - second    one
 +    /// pub struct DoubleString {
 +    ///    ///
 +    ///    ///     - First String:
 +    ///    ///         - needs to be inside here
 +    ///    first_string: String,
 +    ///    ///
 +    ///    ///     - Second String:
 +    ///    ///         - needs to be inside here
 +    ///    second_string: String,
 +    ///}
 +    /// ```
 +    #[clippy::version = "1.41.0"]
 +    pub TABS_IN_DOC_COMMENTS,
 +    style,
 +    "using tabs in doc comments is not recommended"
 +}
 +
 +declare_lint_pass!(TabsInDocComments => [TABS_IN_DOC_COMMENTS]);
 +
 +impl TabsInDocComments {
 +    fn warn_if_tabs_in_doc(cx: &EarlyContext<'_>, attr: &ast::Attribute) {
 +        if let ast::AttrKind::DocComment(_, comment) = attr.kind {
 +            let comment = comment.as_str();
 +
++            for (lo, hi) in get_chunks_of_tabs(comment) {
 +                // +3 skips the opening delimiter
 +                let new_span = Span::new(
 +                    attr.span.lo() + BytePos(3 + lo),
 +                    attr.span.lo() + BytePos(3 + hi),
 +                    attr.span.ctxt(),
 +                    attr.span.parent(),
 +                );
 +                span_lint_and_sugg(
 +                    cx,
 +                    TABS_IN_DOC_COMMENTS,
 +                    new_span,
 +                    "using tabs in doc comments is not recommended",
 +                    "consider using four spaces per tab",
 +                    "    ".repeat((hi - lo) as usize),
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +impl EarlyLintPass for TabsInDocComments {
 +    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attribute: &ast::Attribute) {
 +        Self::warn_if_tabs_in_doc(cx, attribute);
 +    }
 +}
 +
 +///
 +/// scans the string for groups of tabs and returns the start(inclusive) and end positions
 +/// (exclusive) of all groups
 +/// e.g. "sd\tasd\t\taa" will be converted to [(2, 3), (6, 8)] as
 +///       012 3456 7 89
 +///         ^-^  ^---^
 +fn get_chunks_of_tabs(the_str: &str) -> Vec<(u32, u32)> {
 +    let line_length_way_to_long = "doc comment longer than 2^32 chars";
 +    let mut spans: Vec<(u32, u32)> = vec![];
 +    let mut current_start: u32 = 0;
 +
 +    // tracker to decide if the last group of tabs is not closed by a non-tab character
 +    let mut is_active = false;
 +
 +    // Note that we specifically need the char _byte_ indices here, not the positional indexes
 +    // within the char array to deal with multi-byte characters properly. `char_indices` does
 +    // exactly that. It provides an iterator over tuples of the form `(byte position, char)`.
 +    let char_indices: Vec<_> = the_str.char_indices().collect();
 +
 +    if let [(_, '\t')] = char_indices.as_slice() {
 +        return vec![(0, 1)];
 +    }
 +
 +    for entry in char_indices.windows(2) {
 +        match entry {
 +            [(_, '\t'), (_, '\t')] => {
 +                // either string starts with double tab, then we have to set it active,
 +                // otherwise is_active is true anyway
 +                is_active = true;
 +            },
 +            [(_, _), (index_b, '\t')] => {
 +                // as ['\t', '\t'] is excluded, this has to be a start of a tab group,
 +                // set indices accordingly
 +                is_active = true;
 +                current_start = u32::try_from(*index_b).unwrap();
 +            },
 +            [(_, '\t'), (index_b, _)] => {
 +                // this now has to be an end of the group, hence we have to push a new tuple
 +                is_active = false;
 +                spans.push((current_start, u32::try_from(*index_b).unwrap()));
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    // only possible when tabs are at the end, insert last group
 +    if is_active {
 +        spans.push((
 +            current_start,
 +            u32::try_from(char_indices.last().unwrap().0 + 1).expect(line_length_way_to_long),
 +        ));
 +    }
 +
 +    spans
 +}
 +
 +#[cfg(test)]
 +mod tests_for_get_chunks_of_tabs {
 +    use super::get_chunks_of_tabs;
 +
 +    #[test]
 +    fn test_unicode_han_string() {
 +        let res = get_chunks_of_tabs(" \u{4f4d}\t");
 +
 +        assert_eq!(res, vec![(4, 5)]);
 +    }
 +
 +    #[test]
 +    fn test_empty_string() {
 +        let res = get_chunks_of_tabs("");
 +
 +        assert_eq!(res, vec![]);
 +    }
 +
 +    #[test]
 +    fn test_simple() {
 +        let res = get_chunks_of_tabs("sd\t\t\taa");
 +
 +        assert_eq!(res, vec![(2, 5)]);
 +    }
 +
 +    #[test]
 +    fn test_only_t() {
 +        let res = get_chunks_of_tabs("\t\t");
 +
 +        assert_eq!(res, vec![(0, 2)]);
 +    }
 +
 +    #[test]
 +    fn test_only_one_t() {
 +        let res = get_chunks_of_tabs("\t");
 +
 +        assert_eq!(res, vec![(0, 1)]);
 +    }
 +
 +    #[test]
 +    fn test_double() {
 +        let res = get_chunks_of_tabs("sd\tasd\t\taa");
 +
 +        assert_eq!(res, vec![(2, 3), (6, 8)]);
 +    }
 +
 +    #[test]
 +    fn test_start() {
 +        let res = get_chunks_of_tabs("\t\taa");
 +
 +        assert_eq!(res, vec![(0, 2)]);
 +    }
 +
 +    #[test]
 +    fn test_end() {
 +        let res = get_chunks_of_tabs("aa\t\t");
 +
 +        assert_eq!(res, vec![(2, 4)]);
 +    }
 +
 +    #[test]
 +    fn test_start_single() {
 +        let res = get_chunks_of_tabs("\taa");
 +
 +        assert_eq!(res, vec![(0, 1)]);
 +    }
 +
 +    #[test]
 +    fn test_end_single() {
 +        let res = get_chunks_of_tabs("aa\t");
 +
 +        assert_eq!(res, vec![(2, 3)]);
 +    }
 +
 +    #[test]
 +    fn test_no_tabs() {
 +        let res = get_chunks_of_tabs("dsfs");
 +
 +        assert_eq!(res, vec![]);
 +    }
 +}
index ccc49caf47c7a581dbc3ead8e898c21a24d3cdb8,0000000000000000000000000000000000000000..3d3b4a6679dd1e445b956a8777b6a6e889c93b8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,229 -1,0 +1,229 @@@
-     /// Checks for `unsafe` blocks without a `// Safety: ` comment
 +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 +use clippy_utils::is_lint_allowed;
 +use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
 +use rustc_lexer::TokenKind;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::TyCtxt;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{BytePos, Span};
 +use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
-     /// // Safety: references are guaranteed to be non-null.
++    /// Checks for `unsafe` blocks without a `// SAFETY: ` comment
 +    /// explaining why the unsafe operations performed inside
 +    /// the block are safe.
 +    ///
 +    /// ### Why is this bad?
 +    /// Undocumented unsafe blocks can make it difficult to
 +    /// read and maintain code, as well as uncover unsoundness
 +    /// and bugs.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
-             let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
++    /// // SAFETY: references are guaranteed to be non-null.
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub UNDOCUMENTED_UNSAFE_BLOCKS,
 +    restriction,
 +    "creating an unsafe block without explaining why it is safe"
 +}
 +
 +impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
 +
 +#[derive(Default)]
 +pub struct UndocumentedUnsafeBlocks {
 +    pub local_level: u32,
 +    pub local_span: Option<Span>,
 +    // The local was already checked for an overall safety comment
 +    // There is no need to continue checking the blocks in the local
 +    pub local_checked: bool,
 +    // Since we can only check the blocks from expanded macros
 +    // We have to omit the suggestion due to the actual definition
 +    // Not being available to us
 +    pub macro_expansion: bool,
 +}
 +
 +impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
 +    fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
 +        if_chain! {
 +            if !self.local_checked;
 +            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
 +            if !in_external_macro(cx.tcx.sess, block.span);
 +            if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
 +            if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
 +            if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
 +            then {
 +                let mut span = block.span;
 +
 +                if let Some(local_span) = self.local_span {
 +                    span = local_span;
 +
 +                    let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
 +
 +                    if result.unwrap_or(true) {
 +                        self.local_checked = true;
 +                        return;
 +                    }
 +                }
 +
 +                self.lint(cx, span);
 +            }
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
 +        if_chain! {
 +            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
 +            if !in_external_macro(cx.tcx.sess, local.span);
 +            if let Some(init) = local.init;
 +            then {
 +                self.visit_expr(init);
 +
 +                if self.local_level > 0 {
 +                    self.local_span = Some(local.span);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
 +        self.local_level = self.local_level.saturating_sub(1);
 +
 +        if self.local_level == 0 {
 +            self.local_checked = false;
 +            self.local_span = None;
 +        }
 +    }
 +}
 +
 +impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
 +    type Map = Map<'hir>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, ex: &'v Expr<'v>) {
 +        match ex.kind {
 +            ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
 +            _ => walk_expr(self, ex),
 +        }
 +    }
 +}
 +
 +impl UndocumentedUnsafeBlocks {
 +    fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
 +        let map = tcx.hir();
 +        let source_map = tcx.sess.source_map();
 +
 +        let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
 +
 +        let between_span = if block_span.from_expansion() {
 +            self.macro_expansion = true;
 +            enclosing_scope_span.with_hi(block_span.hi()).source_callsite()
 +        } else {
 +            self.macro_expansion = false;
 +            enclosing_scope_span.to(block_span).source_callsite()
 +        };
 +
 +        let file_name = source_map.span_to_filename(between_span);
 +        let source_file = source_map.get_source_file(&file_name)?;
 +
 +        let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
 +        let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
 +        let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
 +
 +        let source_start_pos = source_file.start_pos.0 as usize + lex_start;
 +
 +        let mut pos = 0;
 +        let mut comment = false;
 +
 +        for token in rustc_lexer::tokenize(&src_str) {
 +            match token.kind {
 +                TokenKind::LineComment { doc_style: None }
 +                | TokenKind::BlockComment {
 +                    doc_style: None,
 +                    terminated: true,
 +                } => {
 +                    let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
 +
 +                    if comment_str.contains("SAFETY:") {
 +                        comment = true;
 +                    }
 +                },
 +                // We need to add all whitespace to `pos` before checking the comment's line number
 +                TokenKind::Whitespace => {},
 +                _ => {
 +                    if comment {
 +                        // Get the line number of the "comment" (really wherever the trailing whitespace ended)
 +                        let comment_line_num = source_file
 +                            .lookup_file_pos(BytePos((source_start_pos + pos).try_into().unwrap()))
 +                            .0;
 +                        // Find the block/local's line number
 +                        let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
 +
 +                        // Check the comment is immediately followed by the block/local
 +                        if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
 +                            return Some(true);
 +                        }
 +
 +                        comment = false;
 +                    }
 +                },
 +            }
 +
 +            pos += token.len;
 +        }
 +
 +        Some(false)
 +    }
 +
 +    fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
 +        let source_map = cx.tcx.sess.source_map();
 +
 +        if source_map.is_multiline(span) {
 +            span = source_map.span_until_char(span, '\n');
 +        }
 +
 +        if self.macro_expansion {
 +            span_lint_and_help(
 +                cx,
 +                UNDOCUMENTED_UNSAFE_BLOCKS,
 +                span,
 +                "unsafe block in macro expansion missing a safety comment",
 +                None,
 +                "consider adding a safety comment in the macro definition",
 +            );
 +        } else {
 +            let block_indent = indent_of(cx, span);
++            let suggestion = format!("// SAFETY: ...\n{}", snippet(cx, span, ".."));
 +
 +            span_lint_and_sugg(
 +                cx,
 +                UNDOCUMENTED_UNSAFE_BLOCKS,
 +                span,
 +                "unsafe block missing a safety comment",
 +                "consider adding a safety comment",
 +                reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
 +                Applicability::HasPlaceholders,
 +            );
 +        }
 +    }
 +}
index 44b1989dbc68a4a4eb30b01491b0bc018546235d,0000000000000000000000000000000000000000..64f7a055cd9bd7f72bff009805bccdb575426cb8
mode 100644,000000..100644
--- /dev/null
@@@ -1,79 -1,0 +1,79 @@@
-     if contains_unsafe(&old_str) && !contains_unsafe(&new_str) {
 +use clippy_utils::diagnostics::span_lint;
 +use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind};
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::Ident;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for imports that remove "unsafe" from an item's
 +    /// name.
 +    ///
 +    /// ### Why is this bad?
 +    /// Renaming makes it less clear which traits and
 +    /// structures are unsafe.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// use std::cell::{UnsafeCell as TotallySafeCell};
 +    ///
 +    /// extern crate crossbeam;
 +    /// use crossbeam::{spawn_unsafe as spawn};
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNSAFE_REMOVED_FROM_NAME,
 +    style,
 +    "`unsafe` removed from API names on import"
 +}
 +
 +declare_lint_pass!(UnsafeNameRemoval => [UNSAFE_REMOVED_FROM_NAME]);
 +
 +impl EarlyLintPass for UnsafeNameRemoval {
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 +        if let ItemKind::Use(ref use_tree) = item.kind {
 +            check_use_tree(use_tree, cx, item.span);
 +        }
 +    }
 +}
 +
 +fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
 +    match use_tree.kind {
 +        UseTreeKind::Simple(Some(new_name), ..) => {
 +            let old_name = use_tree
 +                .prefix
 +                .segments
 +                .last()
 +                .expect("use paths cannot be empty")
 +                .ident;
 +            unsafe_to_safe_check(old_name, new_name, cx, span);
 +        },
 +        UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {},
 +        UseTreeKind::Nested(ref nested_use_tree) => {
 +            for &(ref use_tree, _) in nested_use_tree {
 +                check_use_tree(use_tree, cx, span);
 +            }
 +        },
 +    }
 +}
 +
 +fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, span: Span) {
 +    let old_str = old_name.name.as_str();
 +    let new_str = new_name.name.as_str();
++    if contains_unsafe(old_str) && !contains_unsafe(new_str) {
 +        span_lint(
 +            cx,
 +            UNSAFE_REMOVED_FROM_NAME,
 +            span,
 +            &format!(
 +                "removed `unsafe` from the name of `{}` in use as `{}`",
 +                old_str, new_str
 +            ),
 +        );
 +    }
 +}
 +
 +#[must_use]
 +fn contains_unsafe(name: &str) -> bool {
 +    name.contains("Unsafe") || name.contains("unsafe")
 +}
index 01a5691223bfc6ef4db924e6424432aa37970eb2,0000000000000000000000000000000000000000..918fa5f7dc12467bb6a19fd5601756d5ccf027eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,328 -1,0 +1,328 @@@
-                 let unwrappable = match name.as_ref() {
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::higher;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, PathSegment, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::Ty;
 +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 calls of `unwrap[_err]()` that cannot fail.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `if let` or `match` is more idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let option = Some(0);
 +    /// # fn do_something_with(_x: usize) {}
 +    /// if option.is_some() {
 +    ///     do_something_with(option.unwrap())
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// # let option = Some(0);
 +    /// # fn do_something_with(_x: usize) {}
 +    /// if let Some(value) = option {
 +    ///     do_something_with(value)
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNNECESSARY_UNWRAP,
 +    complexity,
 +    "checks for calls of `unwrap[_err]()` that cannot fail"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls of `unwrap[_err]()` that will always fail.
 +    ///
 +    /// ### Why is this bad?
 +    /// If panicking is desired, an explicit `panic!()` should be used.
 +    ///
 +    /// ### Known problems
 +    /// This lint only checks `if` conditions not assignments.
 +    /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let option = Some(0);
 +    /// # fn do_something_with(_x: usize) {}
 +    /// if option.is_none() {
 +    ///     do_something_with(option.unwrap())
 +    /// }
 +    /// ```
 +    ///
 +    /// This code will always panic. The if condition should probably be inverted.
 +    #[clippy::version = "pre 1.29.0"]
 +    pub PANICKING_UNWRAP,
 +    correctness,
 +    "checks for calls of `unwrap[_err]()` that will always fail"
 +}
 +
 +/// Visitor that keeps track of which variables are unwrappable.
 +struct UnwrappableVariablesVisitor<'a, 'tcx> {
 +    unwrappables: Vec<UnwrapInfo<'tcx>>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +/// What kind of unwrappable this is.
 +#[derive(Copy, Clone, Debug)]
 +enum UnwrappableKind {
 +    Option,
 +    Result,
 +}
 +
 +impl UnwrappableKind {
 +    fn success_variant_pattern(self) -> &'static str {
 +        match self {
 +            UnwrappableKind::Option => "Some(..)",
 +            UnwrappableKind::Result => "Ok(..)",
 +        }
 +    }
 +
 +    fn error_variant_pattern(self) -> &'static str {
 +        match self {
 +            UnwrappableKind::Option => "None",
 +            UnwrappableKind::Result => "Err(..)",
 +        }
 +    }
 +}
 +
 +/// Contains information about whether a variable can be unwrapped.
 +#[derive(Copy, Clone, Debug)]
 +struct UnwrapInfo<'tcx> {
 +    /// The variable that is checked
 +    local_id: HirId,
 +    /// The if itself
 +    if_expr: &'tcx Expr<'tcx>,
 +    /// The check, like `x.is_ok()`
 +    check: &'tcx Expr<'tcx>,
 +    /// The check's name, like `is_ok`
 +    check_name: &'tcx PathSegment<'tcx>,
 +    /// The branch where the check takes place, like `if x.is_ok() { .. }`
 +    branch: &'tcx Expr<'tcx>,
 +    /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
 +    safe_to_unwrap: bool,
 +    /// What kind of unwrappable this is.
 +    kind: UnwrappableKind,
 +    /// If the check is the entire condition (`if x.is_ok()`) or only a part of it (`foo() &&
 +    /// x.is_ok()`)
 +    is_entire_condition: bool,
 +}
 +
 +/// Collects the information about unwrappable variables from an if condition
 +/// The `invert` argument tells us whether the condition is negated.
 +fn collect_unwrap_info<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    if_expr: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +    branch: &'tcx Expr<'_>,
 +    invert: bool,
 +    is_entire_condition: bool,
 +) -> Vec<UnwrapInfo<'tcx>> {
 +    fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
 +        is_type_diagnostic_item(cx, ty, sym::Option) && ["is_some", "is_none"].contains(&method_name)
 +    }
 +
 +    fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
 +        is_type_diagnostic_item(cx, ty, sym::Result) && ["is_ok", "is_err"].contains(&method_name)
 +    }
 +
 +    if let ExprKind::Binary(op, left, right) = &expr.kind {
 +        match (invert, op.node) {
 +            (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => {
 +                let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false);
 +                unwrap_info.append(&mut collect_unwrap_info(cx, if_expr, right, branch, invert, false));
 +                return unwrap_info;
 +            },
 +            _ => (),
 +        }
 +    } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind {
 +        return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
 +    } else {
 +        if_chain! {
 +            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
 +            if let Some(local_id) = path_to_local(&args[0]);
 +            let ty = cx.typeck_results().expr_ty(&args[0]);
 +            let name = method_name.ident.as_str();
 +            if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
 +            then {
 +                assert!(args.len() == 1);
++                let unwrappable = match name {
 +                    "is_some" | "is_ok" => true,
 +                    "is_err" | "is_none" => false,
 +                    _ => unreachable!(),
 +                };
 +                let safe_to_unwrap = unwrappable != invert;
 +                let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
 +                    UnwrappableKind::Option
 +                } else {
 +                    UnwrappableKind::Result
 +                };
 +
 +                return vec![
 +                    UnwrapInfo {
 +                        local_id,
 +                        if_expr,
 +                        check: expr,
 +                        check_name: method_name,
 +                        branch,
 +                        safe_to_unwrap,
 +                        kind,
 +                        is_entire_condition,
 +                    }
 +                ]
 +            }
 +        }
 +    }
 +    Vec::new()
 +}
 +
 +impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
 +    fn visit_branch(
 +        &mut self,
 +        if_expr: &'tcx Expr<'_>,
 +        cond: &'tcx Expr<'_>,
 +        branch: &'tcx Expr<'_>,
 +        else_branch: bool,
 +    ) {
 +        let prev_len = self.unwrappables.len();
 +        for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
 +            if is_potentially_mutated(unwrap_info.local_id, cond, self.cx)
 +                || is_potentially_mutated(unwrap_info.local_id, branch, self.cx)
 +            {
 +                // if the variable is mutated, we don't know whether it can be unwrapped:
 +                continue;
 +            }
 +            self.unwrappables.push(unwrap_info);
 +        }
 +        walk_expr(self, branch);
 +        self.unwrappables.truncate(prev_len);
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        // Shouldn't lint when `expr` is in macro.
 +        if in_external_macro(self.cx.tcx.sess, expr.span) {
 +            return;
 +        }
 +        if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) {
 +            walk_expr(self, cond);
 +            self.visit_branch(expr, cond, then, false);
 +            if let Some(else_inner) = r#else {
 +                self.visit_branch(expr, cond, else_inner, true);
 +            }
 +        } else {
 +            // find `unwrap[_err]()` calls:
 +            if_chain! {
 +                if let ExprKind::MethodCall(method_name, _, [self_arg, ..], _) = expr.kind;
 +                if let Some(id) = path_to_local(self_arg);
 +                if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
 +                let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
 +                if let Some(unwrappable) = self.unwrappables.iter()
 +                    .find(|u| u.local_id == id);
 +                // Span contexts should not differ with the conditional branch
 +                if !differing_macro_contexts(unwrappable.branch.span, expr.span);
 +                if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span);
 +                then {
 +                    if call_to_unwrap == unwrappable.safe_to_unwrap {
 +                        let is_entire_condition = unwrappable.is_entire_condition;
 +                        let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id);
 +                        let suggested_pattern = if call_to_unwrap {
 +                            unwrappable.kind.success_variant_pattern()
 +                        } else {
 +                            unwrappable.kind.error_variant_pattern()
 +                        };
 +
 +                        span_lint_and_then(
 +                            self.cx,
 +                            UNNECESSARY_UNWRAP,
 +                            expr.span,
 +                            &format!(
 +                                "called `{}` on `{}` after checking its variant with `{}`",
 +                                method_name.ident.name,
 +                                unwrappable_variable_name,
 +                                unwrappable.check_name.ident.as_str(),
 +                            ),
 +                            |diag| {
 +                                if is_entire_condition {
 +                                    diag.span_suggestion(
 +                                        unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
 +                                        "try",
 +                                        format!(
 +                                            "if let {} = {}",
 +                                            suggested_pattern,
 +                                            unwrappable_variable_name,
 +                                        ),
 +                                        // We don't track how the unwrapped value is used inside the
 +                                        // block or suggest deleting the unwrap, so we can't offer a
 +                                        // fixable solution.
 +                                        Applicability::Unspecified,
 +                                    );
 +                                } else {
 +                                    diag.span_label(unwrappable.check.span, "the check is happening here");
 +                                    diag.help("try using `if let` or `match`");
 +                                }
 +                            },
 +                        );
 +                    } else {
 +                        span_lint_and_then(
 +                            self.cx,
 +                            PANICKING_UNWRAP,
 +                            expr.span,
 +                            &format!("this call to `{}()` will always panic",
 +                            method_name.ident.name),
 +                            |diag| { diag.span_label(unwrappable.check.span, "because of this check"); },
 +                        );
 +                    }
 +                }
 +            }
 +            walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +declare_lint_pass!(Unwrap => [PANICKING_UNWRAP, UNNECESSARY_UNWRAP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Unwrap {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        kind: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        span: Span,
 +        fn_id: HirId,
 +    ) {
 +        if span.from_expansion() {
 +            return;
 +        }
 +
 +        let mut v = UnwrappableVariablesVisitor {
 +            cx,
 +            unwrappables: Vec::new(),
 +        };
 +
 +        walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
 +    }
 +}
index 0c62161e53d437372e120404b5862f8aa03f4d73,0000000000000000000000000000000000000000..7286d0a7bf99b890b2bd0f90aa58e754c6e427ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,127 -1,0 +1,127 @@@
-     || (be_aggressive && ident != &corrected)
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use itertools::Itertools;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Item, ItemKind};
 +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::Ident;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for fully capitalized names and optionally names containing a capitalized acronym.
 +    ///
 +    /// ### Why is this bad?
 +    /// In CamelCase, acronyms count as one word.
 +    /// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
 +    /// for more.
 +    ///
 +    /// By default, the lint only triggers on fully-capitalized names.
 +    /// You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
 +    /// on all camel case names
 +    ///
 +    /// ### Known problems
 +    /// When two acronyms are contiguous, the lint can't tell where
 +    /// the first acronym ends and the second starts, so it suggests to lowercase all of
 +    /// the letters in the second acronym.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct HTTPResponse;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// struct HttpResponse;
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub UPPER_CASE_ACRONYMS,
 +    style,
 +    "capitalized acronyms are against the naming convention"
 +}
 +
 +#[derive(Default)]
 +pub struct UpperCaseAcronyms {
 +    avoid_breaking_exported_api: bool,
 +    upper_case_acronyms_aggressive: bool,
 +}
 +
 +impl UpperCaseAcronyms {
 +    pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
 +        Self {
 +            avoid_breaking_exported_api,
 +            upper_case_acronyms_aggressive: aggressive,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);
 +
 +fn correct_ident(ident: &str) -> String {
 +    let ident = ident.chars().rev().collect::<String>();
 +    let fragments = ident
 +        .split_inclusive(|x: char| !x.is_ascii_lowercase())
 +        .rev()
 +        .map(|x| x.chars().rev().collect::<String>());
 +
 +    let mut ident = fragments.clone().next().unwrap();
 +    for (ref prev, ref curr) in fragments.tuple_windows() {
 +        if [prev, curr]
 +            .iter()
 +            .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
 +        {
 +            ident.push_str(&curr.to_ascii_lowercase());
 +        } else {
 +            ident.push_str(curr);
 +        }
 +    }
 +    ident
 +}
 +
 +fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
 +    let span = ident.span;
 +    let ident = ident.as_str();
 +    let corrected = correct_ident(ident);
 +    // warn if we have pure-uppercase idents
 +    // assume that two-letter words are some kind of valid abbreviation like FP for false positive
 +    // (and don't warn)
 +    if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2)
 +    // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive
 +    // upper-case-acronyms-aggressive config option enabled
++    || (be_aggressive && ident != corrected)
 +    {
 +        span_lint_and_sugg(
 +            cx,
 +            UPPER_CASE_ACRONYMS,
 +            span,
 +            &format!("name `{}` contains a capitalized acronym", ident),
 +            "consider making the acronym lowercase, except the initial letter",
 +            corrected,
 +            Applicability::MaybeIncorrect,
 +        );
 +    }
 +}
 +
 +impl LateLintPass<'_> for UpperCaseAcronyms {
 +    fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
 +        // do not lint public items or in macros
 +        if in_external_macro(cx.sess(), it.span)
 +            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id))
 +        {
 +            return;
 +        }
 +        match it.kind {
 +            ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
 +                check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
 +            },
 +            ItemKind::Enum(ref enumdef, _) => {
 +                // check enum variants seperately because again we only want to lint on private enums and
 +                // the fn check_variant does not know about the vis of the enum of its variants
 +                enumdef
 +                    .variants
 +                    .iter()
 +                    .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
 +            },
 +            _ => {},
 +        }
 +    }
 +}
index 81e9c2e15c97a19b8a4d7220b90576a998b06dc9,0000000000000000000000000000000000000000..e98dcd3cf983b721905c555cb9f2c2aceef18d4d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1302 -1,0 +1,1300 @@@
- use rustc_span::symbol::{Symbol, SymbolStr};
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::match_type;
 +use clippy_utils::{
 +    higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
 +    path_to_res, paths, peel_blocks_with_stmt, SpanlessEq,
 +};
 +use if_chain::if_chain;
 +use rustc_ast as ast;
 +use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
 +use rustc_ast::visit::FnKind;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::CRATE_HIR_ID;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind,
 +    UnOp,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::mir::interpret::ConstValue;
 +use rustc_middle::ty;
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Spanned;
-                         let mut last_name: Option<SymbolStr> = None;
++use rustc_span::symbol::Symbol;
 +use rustc_span::{sym, BytePos, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use std::borrow::{Borrow, Cow};
 +
 +#[cfg(feature = "metadata-collector-lint")]
 +pub mod metadata_collector;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for various things we like to keep tidy in clippy.
 +    ///
 +    /// ### Why is this bad?
 +    /// We like to pretend we're an example of tidy code.
 +    ///
 +    /// ### Example
 +    /// Wrong ordering of the util::paths constants.
 +    pub CLIPPY_LINTS_INTERNAL,
 +    internal,
 +    "various things that will negatively affect your clippy experience"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Ensures every lint is associated to a `LintPass`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The compiler only knows lints via a `LintPass`. Without
 +    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
 +    /// know the name of the lint.
 +    ///
 +    /// ### Known problems
 +    /// Only checks for lints associated using the
 +    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// declare_lint! { pub LINT_1, ... }
 +    /// declare_lint! { pub LINT_2, ... }
 +    /// declare_lint! { pub FORGOTTEN_LINT, ... }
 +    /// // ...
 +    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
 +    /// // missing FORGOTTEN_LINT
 +    /// ```
 +    pub LINT_WITHOUT_LINT_PASS,
 +    internal,
 +    "declaring a lint without associating it in a LintPass"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
 +    /// variant of the function.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `utils::*` variants also add a link to the Clippy documentation to the
 +    /// warning/error messages.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// cx.span_lint(LINT_NAME, "message");
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::span_lint(cx, LINT_NAME, "message");
 +    /// ```
 +    pub COMPILER_LINT_FUNCTIONS,
 +    internal,
 +    "usage of the lint functions of the compiler instead of the utils::* variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.outer().expn_data()` and suggests to use
 +    /// the `cx.outer_expn_data()`
 +    ///
 +    /// ### Why is this bad?
 +    /// `cx.outer_expn_data()` is faster and more concise.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer().expn_data()
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer_expn_data()
 +    /// ```
 +    pub OUTER_EXPN_EXPN_DATA,
 +    internal,
 +    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Not an actual lint. This lint is only meant for testing our customized internal compiler
 +    /// error message by calling `panic`.
 +    ///
 +    /// ### Why is this bad?
 +    /// ICE in large quantities can damage your teeth
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// 🍦🍦🍦🍦🍦
 +    /// ```
 +    pub PRODUCE_ICE,
 +    internal,
 +    "this message should not appear anywhere as we ICE before and don't emit the lint"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for cases of an auto-generated lint without an updated description,
 +    /// i.e. `default lint description`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Indicates that the lint is not finished.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
 +    /// ```
 +    pub DEFAULT_LINT,
 +    internal,
 +    "found 'default lint description' in a lint declaration"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lints `span_lint_and_then` function calls, where the
 +    /// closure argument has only one statement and that statement is a method
 +    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
 +    /// span), `help` or `note`.
 +    ///
 +    /// These usages of `span_lint_and_then` should be replaced with one of the
 +    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
 +    /// `span_lint_and_note`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the wrapper `span_lint_and_*` functions, is more
 +    /// convenient, readable and less error prone.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_suggestion(
 +    ///         expr.span,
 +    ///         help_msg,
 +    ///         sugg.to_string(),
 +    ///         Applicability::MachineApplicable,
 +    ///     );
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_help(expr.span, help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.help(help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_note(expr.span, note_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.note(note_msg);
 +    /// });
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     TEST_LINT,
 +    ///     expr.span,
 +    ///     lint_msg,
 +    ///     help_msg,
 +    ///     sugg.to_string(),
 +    ///     Applicability::MachineApplicable,
 +    /// );
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
 +    /// ```
 +    pub COLLAPSIBLE_SPAN_LINT_CALLS,
 +    internal,
 +    "found collapsible `span_lint_and_then` calls"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `utils::match_type()` on a type diagnostic item
 +    /// and suggests to use `utils::is_type_diagnostic_item()` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `utils::is_type_diagnostic_item()` does not require hardcoded paths.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// utils::match_type(cx, ty, &paths::VEC)
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
 +    /// ```
 +    pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    internal,
 +    "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
 +}
 +
 +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_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for interning symbols that have already been pre-interned and defined as constants.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster and easier to use the symbol constant.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// let _ = sym!(f32);
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// let _ = sym::f32;
 +    /// ```
 +    pub INTERNING_DEFINED_SYMBOL,
 +    internal,
 +    "interning a symbol that is pre-interned and defined as a constant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary conversion from Symbol to a string.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster use symbols directly intead of strings.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// symbol.as_str() == "clippy";
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// symbol == sym::clippy;
 +    /// ```
 +    pub UNNECESSARY_SYMBOL_STR,
 +    internal,
 +    "unnecessary conversion between Symbol and string"
 +}
 +
 +declare_clippy_lint! {
 +    /// Finds unidiomatic usage of `if_chain!`
 +    pub IF_CHAIN_STYLE,
 +    internal,
 +    "non-idiomatic `if_chain!` usage"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for invalid `clippy::version` attributes.
 +    ///
 +    /// Valid values are:
 +    /// * "pre 1.29.0"
 +    /// * any valid semantic version
 +    pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +    internal,
 +    "found an invalid `clippy::version` attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for declared clippy lints without the `clippy::version` attribute.
 +    ///
 +    pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +    internal,
 +    "found clippy lint without `clippy::version` attribute"
 +}
 +
 +declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 +
 +impl EarlyLintPass for ClippyLintsInternal {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
 +        if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
 +            if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
 +                if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
 +                    if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
-                             if let Some(ref last_name) = last_name {
-                                 if **last_name > *name {
++                        let mut last_name: Option<&str> = None;
 +                        for item in items {
 +                            let name = item.ident.as_str();
-         let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
-         let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
++                            if let Some(last_name) = last_name {
++                                if *last_name > *name {
 +                                    span_lint(
 +                                        cx,
 +                                        CLIPPY_LINTS_INTERNAL,
 +                                        item.span,
 +                                        "this constant should be before the previous constant due to lexical \
 +                                         ordering",
 +                                    );
 +                                }
 +                            }
 +                            last_name = Some(name);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug, Default)]
 +pub struct LintWithoutLintPass {
 +    declared_lints: FxHashMap<Symbol, Span>,
 +    registered_lints: FxHashSet<Symbol>,
 +}
 +
 +impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
 +            return;
 +        }
 +
 +        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
 +            if is_lint_ref_type(cx, ty) {
 +                check_invalid_clippy_version_attribute(cx, item);
 +
 +                let expr = &cx.tcx.hir().body(body_id).value;
 +                if_chain! {
 +                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind;
 +                    if let ExprKind::Struct(_, fields, _) = inner_exp.kind;
 +                    let field = fields
 +                        .iter()
 +                        .find(|f| f.ident.as_str() == "desc")
 +                        .expect("lints must have a description field");
 +                    if let ExprKind::Lit(Spanned {
 +                        node: LitKind::Str(ref sym, _),
 +                        ..
 +                    }) = field.expr.kind;
 +                    if sym.as_str() == "default lint description";
 +
 +                    then {
 +                        span_lint(
 +                            cx,
 +                            DEFAULT_LINT,
 +                            item.span,
 +                            &format!("the lint `{}` has the default lint description", item.ident.name),
 +                        );
 +                    }
 +                }
 +                self.declared_lints.insert(item.ident.name, item.span);
 +            }
 +        } else if is_expn_of(item.span, "impl_lint_pass").is_some()
 +            || is_expn_of(item.span, "declare_lint_pass").is_some()
 +        {
 +            if let hir::ItemKind::Impl(hir::Impl {
 +                of_trait: None,
 +                items: impl_item_refs,
 +                ..
 +            }) = item.kind
 +            {
 +                let mut collector = LintCollector {
 +                    output: &mut self.registered_lints,
 +                    cx,
 +                };
 +                let body_id = cx.tcx.hir().body_owned_by(
 +                    impl_item_refs
 +                        .iter()
 +                        .find(|iiref| iiref.ident.as_str() == "get_lints")
 +                        .expect("LintPass needs to implement get_lints")
 +                        .id
 +                        .hir_id(),
 +                );
 +                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
 +            }
 +        }
 +    }
 +
 +    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
 +        if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
 +            return;
 +        }
 +
 +        for (lint_name, &lint_span) in &self.declared_lints {
 +            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
 +            // file points to "<rustc macros>".
 +            // `compiletest-rs` thinks that's an error in a different file and
 +            // just ignores it. This causes the test in compile-fail/lint_pass
 +            // not able to capture the error.
 +            // Therefore, we need to climb the macro expansion tree and find the
 +            // actual span that invoked `declare_tool_lint!`:
 +            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
 +
 +            if !self.registered_lints.contains(lint_name) {
 +                span_lint(
 +                    cx,
 +                    LINT_WITHOUT_LINT_PASS,
 +                    lint_span,
 +                    &format!("the lint `{}` is not added to any `LintPass`", lint_name),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
 +    if let TyKind::Rptr(
 +        _,
 +        MutTy {
 +            ty: inner,
 +            mutbl: Mutability::Not,
 +        },
 +    ) = ty.kind
 +    {
 +        if let TyKind::Path(ref path) = inner.kind {
 +            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
 +                return match_def_path(cx, def_id, &paths::LINT);
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
 +    if let Some(value) = extract_clippy_version_value(cx, item) {
 +        // The `sym!` macro doesn't work as it only expects a single token.
 +        // It's better to keep it this way and have a direct `Symbol::intern` call here.
 +        if value == Symbol::intern("pre 1.29.0") {
 +            return;
 +        }
 +
 +        if RustcVersion::parse(&*value.as_str()).is_err() {
 +            span_lint_and_help(
 +                cx,
 +                INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +                item.span,
 +                "this item has an invalid `clippy::version` attribute",
 +                None,
 +                "please use a valid sematic version, see `doc/adding_lints.md`",
 +            );
 +        }
 +    } else {
 +        span_lint_and_help(
 +            cx,
 +            MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +            item.span,
 +            "this lint is missing the `clippy::version` attribute or version value",
 +            None,
 +            "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
 +        );
 +    }
 +}
 +
 +/// This function extracts the version value of a `clippy::version` attribute if the given value has
 +/// one
 +fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
 +    let attrs = cx.tcx.hir().attrs(item.hir_id());
 +    attrs.iter().find_map(|attr| {
 +        if_chain! {
 +            // Identify attribute
 +            if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
 +            if let [tool_name, attr_name] = &attr_kind.path.segments[..];
 +            if tool_name.ident.name == sym::clippy;
 +            if attr_name.ident.name == sym::version;
 +            if let Some(version) = attr.value_str();
 +            then {
 +                Some(version)
 +            } else {
 +                None
 +            }
 +        }
 +    })
 +}
 +
 +struct LintCollector<'a, 'tcx> {
 +    output: &'a mut FxHashSet<Symbol>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
 +        if path.segments.len() == 1 {
 +            self.output.insert(path.segments[0].ident.name);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +}
 +
 +#[derive(Clone, Default)]
 +pub struct CompilerLintFunctions {
 +    map: FxHashMap<&'static str, &'static str>,
 +}
 +
 +impl CompilerLintFunctions {
 +    #[must_use]
 +    pub fn new() -> Self {
 +        let mut map = FxHashMap::default();
 +        map.insert("span_lint", "utils::span_lint");
 +        map.insert("struct_span_lint", "utils::span_lint");
 +        map.insert("lint", "utils::span_lint");
 +        map.insert("span_lint_note", "utils::span_lint_and_note");
 +        map.insert("span_lint_help", "utils::span_lint_and_help");
 +        Self { map }
 +    }
 +}
 +
 +impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
 +            let fn_name = path.ident;
 +            if let Some(sugg) = self.map.get(&*fn_name.as_str());
 +            let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +            if match_type(cx, ty, &paths::EARLY_CONTEXT)
 +                || match_type(cx, ty, &paths::LATE_CONTEXT);
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    COMPILER_LINT_FUNCTIONS,
 +                    path.ident.span,
 +                    "usage of a compiler lint function",
 +                    None,
 +                    &format!("please use the Clippy variant of this function: `{}`", sugg),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
 +
 +impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
 +            return;
 +        }
 +
 +        let (method_names, arg_lists, spans) = method_calls(expr, 2);
-             let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
++        let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
 +        if_chain! {
 +            if let ["expn_data", "outer_expn"] = method_names.as_slice();
 +            let args = arg_lists[1];
 +            if args.len() == 1;
 +            let self_arg = &args[0];
 +            let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +            if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    OUTER_EXPN_EXPN_DATA,
 +                    spans[1].with_hi(expr.span.hi()),
 +                    "usage of `outer_expn().expn_data()`",
 +                    "try",
 +                    "outer_expn_data()".to_string(),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
 +
 +impl EarlyLintPass for ProduceIce {
 +    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
 +        assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
 +    }
 +}
 +
 +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
 +        FnKind::Closure(..) => false,
 +    }
 +}
 +
 +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(func, and_then_args) = expr.kind;
 +            if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
 +            if and_then_args.len() == 5;
 +            if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
 +            let body = cx.tcx.hir().body(*body_id);
 +            let only_expr = peel_blocks_with_stmt(&body.value);
 +            if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind;
 +            then {
 +                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
 +                let mut sle = SpanlessEq::new(cx).deny_side_effects();
 +                match &*ps.ident.as_str() {
 +                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
 +                    },
 +                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
 +                    },
 +                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
 +                    },
 +                    "help" => {
 +                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
 +                    }
 +                    "note" => {
 +                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
 +                    }
 +                    _  => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct AndThenSnippets<'a> {
 +    cx: Cow<'a, str>,
 +    lint: Cow<'a, str>,
 +    span: Cow<'a, str>,
 +    msg: Cow<'a, str>,
 +}
 +
 +fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
 +    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
 +    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
 +    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
 +    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
 +
 +    AndThenSnippets {
 +        cx: cx_snippet,
 +        lint: lint_snippet,
 +        span: span_snippet,
 +        msg: msg_snippet,
 +    }
 +}
 +
 +struct SpanSuggestionSnippets<'a> {
 +    help: Cow<'a, str>,
 +    sugg: Cow<'a, str>,
 +    applicability: Cow<'a, str>,
 +}
 +
 +fn span_suggestion_snippets<'a, 'hir>(
 +    cx: &LateContext<'_>,
 +    span_call_args: &'hir [Expr<'hir>],
 +) -> SpanSuggestionSnippets<'a> {
 +    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
 +    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
 +
 +    SpanSuggestionSnippets {
 +        help: help_snippet,
 +        sugg: sugg_snippet,
 +        applicability: applicability_snippet,
 +    }
 +}
 +
 +fn suggest_suggestion(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
 +) {
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            span_suggestion_snippets.help,
 +            span_suggestion_snippets.sugg,
 +            span_suggestion_snippets.applicability
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_help(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    help: &str,
 +    with_span: bool,
 +) {
 +    let option_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_help({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            &option_span,
 +            help
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_note(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    note: &str,
 +    with_span: bool,
 +) {
 +    let note_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collspible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_note({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            note_span,
 +            note
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            // Check if this is a call to utils::match_type()
 +            if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
 +            if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
 +            // Extract the path to the matched type
 +            if let Some(segments) = path_to_matched_type(cx, ty_path);
- fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
++            let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
 +            if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
 +            // Check if the matched type is a diagnostic item
 +            if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
 +            then {
 +                // TODO: check paths constants from external crates.
 +                let cx_snippet = snippet(cx, context.span, "_");
 +                let ty_snippet = snippet(cx, ty.span, "_");
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +                    expr.span,
 +                    "usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
 +                    "try",
 +                    format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
 +
-             let segments: Vec<SymbolStr> = exprs
++fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> {
 +    use rustc_hir::ItemKind;
 +
 +    match &expr.kind {
 +        ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
 +        ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
 +            Res::Local(hir_id) => {
 +                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
 +                if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
 +                    if let Some(init) = local.init {
 +                        return path_to_matched_type(cx, init);
 +                    }
 +                }
 +            },
 +            Res::Def(DefKind::Const | DefKind::Static, def_id) => {
 +                if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
 +                    if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
 +                        let body = cx.tcx.hir().body(body_id);
 +                        return path_to_matched_type(cx, &body.value);
 +                    }
 +                }
 +            },
 +            _ => {},
 +        },
 +        ExprKind::Array(exprs) => {
-                             return Some(sym.as_str());
++            let segments: Vec<Symbol> = exprs
 +                .iter()
 +                .filter_map(|expr| {
 +                    if let ExprKind::Lit(lit) = &expr.kind {
 +                        if let LitKind::Str(sym, _) = lit.node {
-         // SymbolStr might be de-referenced: `&*symbol.as_str()`
++                            return Some(sym);
 +                        }
 +                    }
 +
 +                    None
 +                })
 +                .collect();
 +
 +            if segments.len() == exprs.len() {
 +                return Some(segments);
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    None
 +}
 +
 +// 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 path_to_res(cx, path) != Res::Err {
 +        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();
 +    for item_def_id in lang_items.items().iter().flatten() {
 +        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()..] {
 +                for child in cx.tcx.item_children(*item_def_id) {
 +                    if child.ident.name == *item {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +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");
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Default)]
 +pub struct InterningDefinedSymbol {
 +    // Maps the symbol value to the constant DefId.
 +    symbol_map: FxHashMap<u32, DefId>,
 +}
 +
 +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
 +
 +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
 +    fn check_crate(&mut self, cx: &LateContext<'_>) {
 +        if !self.symbol_map.is_empty() {
 +            return;
 +        }
 +
 +        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
 +            if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
 +                for item in cx.tcx.item_children(def_id).iter() {
 +                    if_chain! {
 +                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
 +                        let ty = cx.tcx.type_of(item_def_id);
 +                        if match_type(cx, ty, &paths::SYMBOL);
 +                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
 +                        if let Ok(value) = value.to_u32();
 +                        then {
 +                            self.symbol_map.insert(value, item_def_id);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(func, [arg]) = &expr.kind;
 +            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
 +            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
 +            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
 +            let value = Symbol::intern(&arg).as_u32();
 +            if let Some(&def_id) = self.symbol_map.get(&value);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    INTERNING_DEFINED_SYMBOL,
 +                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
 +                    "interning a defined symbol",
 +                    "try",
 +                    cx.tcx.def_path_str(def_id),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +        if let ExprKind::Binary(op, left, right) = expr.kind {
 +            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
 +                let data = [
 +                    (left, self.symbol_str_expr(left, cx)),
 +                    (right, self.symbol_str_expr(right, cx)),
 +                ];
 +                match data {
 +                    // both operands are a symbol string
 +                    [(_, Some(left)), (_, Some(right))] => {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            UNNECESSARY_SYMBOL_STR,
 +                            expr.span,
 +                            "unnecessary `Symbol` to string conversion",
 +                            "try",
 +                            format!(
 +                                "{} {} {}",
 +                                left.as_symbol_snippet(cx),
 +                                op.node.as_str(),
 +                                right.as_symbol_snippet(cx),
 +                            ),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                    // one of the operands is a symbol string
 +                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
 +                        // creating an owned string for comparison
 +                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                UNNECESSARY_SYMBOL_STR,
 +                                expr.span,
 +                                "unnecessary string allocation",
 +                                "try",
 +                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    },
 +                    // nothing found
 +                    [(_, None), (_, None)] => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl InterningDefinedSymbol {
 +    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
 +        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
 +        static SYMBOL_STR_PATHS: &[&[&str]] = &[
 +            &paths::SYMBOL_AS_STR,
 +            &paths::SYMBOL_TO_IDENT_STRING,
 +            &paths::TO_STRING_METHOD,
 +        ];
 +        let call = if_chain! {
 +            if let ExprKind::AddrOf(_, _, e) = expr.kind;
 +            if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
 +            then { e } else { expr }
 +        };
 +        if_chain! {
 +            // is a method call
 +            if let ExprKind::MethodCall(_, _, [item], _) = call.kind;
 +            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
 +            let ty = cx.typeck_results().expr_ty(item);
 +            // ...on either an Ident or a Symbol
 +            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
 +                Some(false)
 +            } else if match_type(cx, ty, &paths::IDENT) {
 +                Some(true)
 +            } else {
 +                None
 +            };
 +            // ...which converts it to a string
 +            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
 +            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
 +            then {
 +                let is_to_owned = path.last().unwrap().ends_with("string");
 +                return Some(SymbolStrExpr::Expr {
 +                    item,
 +                    is_ident,
 +                    is_to_owned,
 +                });
 +            }
 +        }
 +        // is a string constant
 +        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
 +            let value = Symbol::intern(&s).as_u32();
 +            // ...which matches a symbol constant
 +            if let Some(&def_id) = self.symbol_map.get(&value) {
 +                return Some(SymbolStrExpr::Const(def_id));
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +enum SymbolStrExpr<'tcx> {
 +    /// a string constant with a corresponding symbol constant
 +    Const(DefId),
 +    /// a "symbol to string" expression like `symbol.as_str()`
 +    Expr {
 +        /// part that evaluates to `Symbol` or `Ident`
 +        item: &'tcx Expr<'tcx>,
 +        is_ident: bool,
 +        /// whether an owned `String` is created like `to_ident_string()`
 +        is_to_owned: bool,
 +    },
 +}
 +
 +impl<'tcx> SymbolStrExpr<'tcx> {
 +    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
 +    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
 +        match *self {
 +            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
 +            Self::Expr { item, is_ident, .. } => {
 +                let mut snip = snippet(cx, item.span.source_callsite(), "..");
 +                if is_ident {
 +                    // get `Ident.name`
 +                    snip.to_mut().push_str(".name");
 +                }
 +                snip
 +            },
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
 +        let (local, after, if_chain_span) = if_chain! {
 +            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
 +            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
 +            then { (local, after, if_chain_span) } else { return }
 +        };
 +        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be above the `if_chain!`",
 +            );
 +        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be inside `then { .. }`",
 +            );
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
 +            (cond, then, r#else.is_some())
 +        } else {
 +            return;
 +        };
 +        let then_block = match then.kind {
 +            ExprKind::Block(block, _) => block,
 +            _ => return,
 +        };
 +        let if_chain_span = is_expn_of(expr.span, "if_chain");
 +        if !els {
 +            check_nested_if_chains(cx, expr, then_block, if_chain_span);
 +        }
 +        let if_chain_span = match if_chain_span {
 +            None => return,
 +            Some(span) => span,
 +        };
 +        // check for `if a && b;`
 +        if_chain! {
 +            if let ExprKind::Binary(op, _, _) = cond.kind;
 +            if op.node == BinOpKind::And;
 +            if cx.sess().source_map().is_multiline(cond.span);
 +            then {
 +                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
 +            }
 +        }
 +        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
 +            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
 +        {
 +            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
 +        }
 +    }
 +}
 +
 +fn check_nested_if_chains(
 +    cx: &LateContext<'_>,
 +    if_expr: &Expr<'_>,
 +    then_block: &Block<'_>,
 +    if_chain_span: Option<Span>,
 +) {
 +    #[rustfmt::skip]
 +    let (head, tail) = match *then_block {
 +        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
 +        Block {
 +            stmts: &[
 +                ref head @ ..,
 +                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
 +            ],
 +            ..
 +        } => (head, tail),
 +        _ => return,
 +    };
 +    if_chain! {
 +        if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
 +        let sm = cx.sess().source_map();
 +        if head
 +            .iter()
 +            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
 +        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
 +        then {} else { return }
 +    }
 +    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
 +        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
 +        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
 +        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
 +        _ => return,
 +    };
 +    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
 +        let (span, msg) = match head {
 +            [] => return,
 +            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
 +            [a, .., b] => (
 +                a.span.to(b.span),
 +                "these `let` statements can also be in the `if_chain!`",
 +            ),
 +        };
 +        diag.span_help(span, msg);
 +    });
 +}
 +
 +fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
 +    cx.tcx
 +        .hir()
 +        .parent_iter(hir_id)
 +        .find(|(_, node)| {
 +            #[rustfmt::skip]
 +            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
 +        })
 +        .map_or(false, |(id, _)| {
 +            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
 +        })
 +}
 +
 +/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
 +/// of the `then {..}` portion of an `if_chain!`
 +fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
 +    let span = if let [stmt, ..] = stmts {
 +        stmt.span
 +    } else if let Some(expr) = expr {
 +        expr.span
 +    } else {
 +        // empty `then {}`
 +        return true;
 +    };
 +    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
 +}
 +
 +/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
 +fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
 +    let mut span = local.pat.span;
 +    if let Some(init) = local.init {
 +        span = span.to(init.span);
 +    }
 +    span.adjust(if_chain_span.ctxt().outer_expn());
 +    let sm = cx.sess().source_map();
 +    let span = sm.span_extend_to_prev_str(span, "let", false);
 +    let span = sm.span_extend_to_next_char(span, ';', false);
 +    Span::new(
 +        span.lo() - BytePos(3),
 +        span.hi() + BytePos(1),
 +        span.ctxt(),
 +        span.parent(),
 +    )
 +}
index dc5ec5f229518eda886895e80a633a30aefb8052,0000000000000000000000000000000000000000..5c024612f8eba85711aa188d834b663c58a3790f
mode 100644,000000..100644
--- /dev/null
@@@ -1,636 -1,0 +1,644 @@@
-                     let def_path: Vec<&str> = def_path.iter().take(4).map(|s| s.as_str()).collect();
 +#![allow(clippy::float_cmp)]
 +
 +use crate::{clip, is_direct_expn_of, sext, unsext};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, LitFloatType, LitKind};
 +use rustc_data_structures::sync::Lrc;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 +use rustc_lint::LateContext;
 +use rustc_middle::mir::interpret::Scalar;
 +use rustc_middle::ty::subst::{Subst, SubstsRef};
 +use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
 +use rustc_middle::{bug, span_bug};
 +use rustc_span::symbol::Symbol;
 +use std::cmp::Ordering::{self, Equal};
 +use std::convert::TryInto;
 +use std::hash::{Hash, Hasher};
 +use std::iter;
 +
 +/// A `LitKind`-like enum to fold constant `Expr`s into.
 +#[derive(Debug, Clone)]
 +pub enum Constant {
 +    /// A `String` (e.g., "abc").
 +    Str(String),
 +    /// A binary string (e.g., `b"abc"`).
 +    Binary(Lrc<[u8]>),
 +    /// A single `char` (e.g., `'a'`).
 +    Char(char),
 +    /// An integer's bit representation.
 +    Int(u128),
 +    /// An `f32`.
 +    F32(f32),
 +    /// An `f64`.
 +    F64(f64),
 +    /// `true` or `false`.
 +    Bool(bool),
 +    /// An array of constants.
 +    Vec(Vec<Constant>),
 +    /// Also an array, but with only one constant, repeated N times.
 +    Repeat(Box<Constant>, u64),
 +    /// A tuple of constants.
 +    Tuple(Vec<Constant>),
 +    /// A raw pointer.
 +    RawPtr(u128),
 +    /// A reference
 +    Ref(Box<Constant>),
 +    /// A literal with syntax error.
 +    Err(Symbol),
 +}
 +
 +impl PartialEq for Constant {
 +    fn eq(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (&Self::Str(ref ls), &Self::Str(ref rs)) => ls == rs,
 +            (&Self::Binary(ref l), &Self::Binary(ref r)) => l == r,
 +            (&Self::Char(l), &Self::Char(r)) => l == r,
 +            (&Self::Int(l), &Self::Int(r)) => l == r,
 +            (&Self::F64(l), &Self::F64(r)) => {
 +                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
 +                // `Fw32 == Fw64`, so don’t compare them.
 +                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
 +                l.to_bits() == r.to_bits()
 +            },
 +            (&Self::F32(l), &Self::F32(r)) => {
 +                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
 +                // `Fw32 == Fw64`, so don’t compare them.
 +                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
 +                f64::from(l).to_bits() == f64::from(r).to_bits()
 +            },
 +            (&Self::Bool(l), &Self::Bool(r)) => l == r,
 +            (&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r,
 +            (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
 +            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb,
 +            // TODO: are there inter-type equalities?
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Hash for Constant {
 +    fn hash<H>(&self, state: &mut H)
 +    where
 +        H: Hasher,
 +    {
 +        std::mem::discriminant(self).hash(state);
 +        match *self {
 +            Self::Str(ref s) => {
 +                s.hash(state);
 +            },
 +            Self::Binary(ref b) => {
 +                b.hash(state);
 +            },
 +            Self::Char(c) => {
 +                c.hash(state);
 +            },
 +            Self::Int(i) => {
 +                i.hash(state);
 +            },
 +            Self::F32(f) => {
 +                f64::from(f).to_bits().hash(state);
 +            },
 +            Self::F64(f) => {
 +                f.to_bits().hash(state);
 +            },
 +            Self::Bool(b) => {
 +                b.hash(state);
 +            },
 +            Self::Vec(ref v) | Self::Tuple(ref v) => {
 +                v.hash(state);
 +            },
 +            Self::Repeat(ref c, l) => {
 +                c.hash(state);
 +                l.hash(state);
 +            },
 +            Self::RawPtr(u) => {
 +                u.hash(state);
 +            },
 +            Self::Ref(ref r) => {
 +                r.hash(state);
 +            },
 +            Self::Err(ref s) => {
 +                s.hash(state);
 +            },
 +        }
 +    }
 +}
 +
 +impl Constant {
 +    pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
 +        match (left, right) {
 +            (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
 +            (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
 +            (&Self::Int(l), &Self::Int(r)) => {
 +                if let ty::Int(int_ty) = *cmp_type.kind() {
 +                    Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
 +                } else {
 +                    Some(l.cmp(&r))
 +                }
 +            },
 +            (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
 +            (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
 +            (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
 +            (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => iter::zip(l, r)
 +                .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
 +                .find(|r| r.map_or(true, |o| o != Ordering::Equal))
 +                .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
 +            (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
 +                match Self::partial_cmp(tcx, cmp_type, lv, rv) {
 +                    Some(Equal) => Some(ls.cmp(rs)),
 +                    x => x,
 +                }
 +            },
 +            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
 +            // TODO: are there any useful inter-type orderings?
 +            _ => None,
 +        }
 +    }
 +
 +    /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
 +    pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
 +        if let Constant::Int(const_int) = *self {
 +            match *val_type.kind() {
 +                ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
 +                ty::Uint(_) => Some(FullInt::U(const_int)),
 +                _ => None,
 +            }
 +        } else {
 +            None
 +        }
 +    }
++
++    #[must_use]
++    pub fn peel_refs(mut self) -> Self {
++        while let Constant::Ref(r) = self {
++            self = *r;
++        }
++        self
++    }
 +}
 +
 +/// Parses a `LitKind` to a `Constant`.
 +pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
 +    match *lit {
 +        LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
 +        LitKind::Byte(b) => Constant::Int(u128::from(b)),
 +        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
 +        LitKind::Char(c) => Constant::Char(c),
 +        LitKind::Int(n, _) => Constant::Int(n),
 +        LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
 +            ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
 +            ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
 +        },
 +        LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
 +            ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
 +            ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
 +            _ => bug!(),
 +        },
 +        LitKind::Bool(b) => Constant::Bool(b),
 +        LitKind::Err(s) => Constant::Err(s),
 +    }
 +}
 +
 +pub fn constant<'tcx>(
 +    lcx: &LateContext<'tcx>,
 +    typeck_results: &ty::TypeckResults<'tcx>,
 +    e: &Expr<'_>,
 +) -> Option<(Constant, bool)> {
 +    let mut cx = ConstEvalLateContext {
 +        lcx,
 +        typeck_results,
 +        param_env: lcx.param_env,
 +        needed_resolution: false,
 +        substs: lcx.tcx.intern_substs(&[]),
 +    };
 +    cx.expr(e).map(|cst| (cst, cx.needed_resolution))
 +}
 +
 +pub fn constant_simple<'tcx>(
 +    lcx: &LateContext<'tcx>,
 +    typeck_results: &ty::TypeckResults<'tcx>,
 +    e: &Expr<'_>,
 +) -> Option<Constant> {
 +    constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
 +}
 +
 +pub fn constant_full_int(
 +    lcx: &LateContext<'tcx>,
 +    typeck_results: &ty::TypeckResults<'tcx>,
 +    e: &Expr<'_>,
 +) -> Option<FullInt> {
 +    constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
 +}
 +
 +#[derive(Copy, Clone, Debug, Eq)]
 +pub enum FullInt {
 +    S(i128),
 +    U(u128),
 +}
 +
 +impl PartialEq for FullInt {
 +    #[must_use]
 +    fn eq(&self, other: &Self) -> bool {
 +        self.cmp(other) == Ordering::Equal
 +    }
 +}
 +
 +impl PartialOrd for FullInt {
 +    #[must_use]
 +    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 +        Some(self.cmp(other))
 +    }
 +}
 +
 +impl Ord for FullInt {
 +    #[must_use]
 +    fn cmp(&self, other: &Self) -> Ordering {
 +        use FullInt::{S, U};
 +
 +        fn cmp_s_u(s: i128, u: u128) -> Ordering {
 +            u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
 +        }
 +
 +        match (*self, *other) {
 +            (S(s), S(o)) => s.cmp(&o),
 +            (U(s), U(o)) => s.cmp(&o),
 +            (S(s), U(o)) => cmp_s_u(s, o),
 +            (U(s), S(o)) => cmp_s_u(o, s).reverse(),
 +        }
 +    }
 +}
 +
 +/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
 +pub fn constant_context<'a, 'tcx>(
 +    lcx: &'a LateContext<'tcx>,
 +    typeck_results: &'a ty::TypeckResults<'tcx>,
 +) -> ConstEvalLateContext<'a, 'tcx> {
 +    ConstEvalLateContext {
 +        lcx,
 +        typeck_results,
 +        param_env: lcx.param_env,
 +        needed_resolution: false,
 +        substs: lcx.tcx.intern_substs(&[]),
 +    }
 +}
 +
 +pub struct ConstEvalLateContext<'a, 'tcx> {
 +    lcx: &'a LateContext<'tcx>,
 +    typeck_results: &'a ty::TypeckResults<'tcx>,
 +    param_env: ty::ParamEnv<'tcx>,
 +    needed_resolution: bool,
 +    substs: SubstsRef<'tcx>,
 +}
 +
 +impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 +    /// Simple constant folding: Insert an expression, get a constant or none.
 +    pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
 +        match e.kind {
 +            ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
 +            ExprKind::Block(block, _) => self.block(block),
 +            ExprKind::Lit(ref lit) => {
 +                if is_direct_expn_of(e.span, "cfg").is_some() {
 +                    None
 +                } else {
 +                    Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
 +                }
 +            },
 +            ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
 +            ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
 +            ExprKind::Repeat(value, _) => {
 +                let n = match self.typeck_results.expr_ty(e).kind() {
 +                    ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
 +                    _ => span_bug!(e.span, "typeck error"),
 +                };
 +                self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
 +            },
 +            ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
 +                UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
 +                UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
 +                UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
 +            }),
 +            ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
 +            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
 +            ExprKind::Call(callee, args) => {
 +                // We only handle a few const functions for now.
 +                if_chain! {
 +                    if args.is_empty();
 +                    if let ExprKind::Path(qpath) = &callee.kind;
 +                    let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
 +                    if let Some(def_id) = res.opt_def_id();
 +                    let def_path = self.lcx.get_def_path(def_id);
++                    let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect();
 +                    if let ["core", "num", int_impl, "max_value"] = *def_path;
 +                    then {
 +                       let value = match int_impl {
 +                           "<impl i8>" => i8::MAX as u128,
 +                           "<impl i16>" => i16::MAX as u128,
 +                           "<impl i32>" => i32::MAX as u128,
 +                           "<impl i64>" => i64::MAX as u128,
 +                           "<impl i128>" => i128::MAX as u128,
 +                           _ => return None,
 +                       };
 +                       Some(Constant::Int(value))
 +                    }
 +                    else {
 +                        None
 +                    }
 +                }
 +            },
 +            ExprKind::Index(arr, index) => self.index(arr, index),
 +            ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
 +            // TODO: add other expressions.
 +            _ => None,
 +        }
 +    }
 +
 +    #[allow(clippy::cast_possible_wrap)]
 +    fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
 +        use self::Constant::{Bool, Int};
 +        match *o {
 +            Bool(b) => Some(Bool(!b)),
 +            Int(value) => {
 +                let value = !value;
 +                match *ty.kind() {
 +                    ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
 +                    ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
 +                    _ => None,
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
 +        use self::Constant::{Int, F32, F64};
 +        match *o {
 +            Int(value) => {
 +                let ity = match *ty.kind() {
 +                    ty::Int(ity) => ity,
 +                    _ => return None,
 +                };
 +                // sign extend
 +                let value = sext(self.lcx.tcx, value, ity);
 +                let value = value.checked_neg()?;
 +                // clear unused bits
 +                Some(Int(unsext(self.lcx.tcx, value, ity)))
 +            },
 +            F32(f) => Some(F32(-f)),
 +            F64(f) => Some(F64(-f)),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Create `Some(Vec![..])` of all constants, unless there is any
 +    /// non-constant part.
 +    fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
 +        vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
 +    }
 +
 +    /// Lookup a possibly constant expression from an `ExprKind::Path`.
 +    fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
 +        let res = self.typeck_results.qpath_res(qpath, id);
 +        match res {
 +            Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
 +                let substs = self.typeck_results.node_substs(id);
 +                let substs = if self.substs.is_empty() {
 +                    substs
 +                } else {
 +                    substs.subst(self.lcx.tcx, self.substs)
 +                };
 +
 +                let result = self
 +                    .lcx
 +                    .tcx
 +                    .const_eval_resolve(
 +                        self.param_env,
 +                        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
 +                        None,
 +                    )
 +                    .ok()
 +                    .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
 +                let result = miri_to_const(result);
 +                if result.is_some() {
 +                    self.needed_resolution = true;
 +                }
 +                result
 +            },
 +            // FIXME: cover all usable cases.
 +            _ => None,
 +        }
 +    }
 +
 +    fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
 +        let lhs = self.expr(lhs);
 +        let index = self.expr(index);
 +
 +        match (lhs, index) {
 +            (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) {
 +                Some(Constant::F32(x)) => Some(Constant::F32(*x)),
 +                Some(Constant::F64(x)) => Some(Constant::F64(*x)),
 +                _ => None,
 +            },
 +            (Some(Constant::Vec(vec)), _) => {
 +                if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
 +                    match vec.get(0) {
 +                        Some(Constant::F32(x)) => Some(Constant::F32(*x)),
 +                        Some(Constant::F64(x)) => Some(Constant::F64(*x)),
 +                        _ => None,
 +                    }
 +                } else {
 +                    None
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    /// A block can only yield a constant if it only has one constant expression.
 +    fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
 +        if block.stmts.is_empty() {
 +            block.expr.as_ref().and_then(|b| self.expr(b))
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
 +        if let Some(Constant::Bool(b)) = self.expr(cond) {
 +            if b {
 +                self.expr(&*then)
 +            } else {
 +                otherwise.as_ref().and_then(|expr| self.expr(expr))
 +            }
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
 +        let l = self.expr(left)?;
 +        let r = self.expr(right);
 +        match (l, r) {
 +            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
 +                ty::Int(ity) => {
 +                    let l = sext(self.lcx.tcx, l, ity);
 +                    let r = sext(self.lcx.tcx, r, ity);
 +                    let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
 +                    match op.node {
 +                        BinOpKind::Add => l.checked_add(r).map(zext),
 +                        BinOpKind::Sub => l.checked_sub(r).map(zext),
 +                        BinOpKind::Mul => l.checked_mul(r).map(zext),
 +                        BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
 +                        BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
 +                        BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
 +                        BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
 +                        BinOpKind::BitXor => Some(zext(l ^ r)),
 +                        BinOpKind::BitOr => Some(zext(l | r)),
 +                        BinOpKind::BitAnd => Some(zext(l & r)),
 +                        BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                        BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                        BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                        BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                        BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                        BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                        _ => None,
 +                    }
 +                },
 +                ty::Uint(_) => match op.node {
 +                    BinOpKind::Add => l.checked_add(r).map(Constant::Int),
 +                    BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
 +                    BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
 +                    BinOpKind::Div => l.checked_div(r).map(Constant::Int),
 +                    BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
 +                    BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
 +                    BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
 +                    BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
 +                    BinOpKind::BitOr => Some(Constant::Int(l | r)),
 +                    BinOpKind::BitAnd => Some(Constant::Int(l & r)),
 +                    BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                    BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                    BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                    BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                    BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                    BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                    _ => None,
 +                },
 +                _ => None,
 +            },
 +            (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
 +                BinOpKind::Add => Some(Constant::F32(l + r)),
 +                BinOpKind::Sub => Some(Constant::F32(l - r)),
 +                BinOpKind::Mul => Some(Constant::F32(l * r)),
 +                BinOpKind::Div => Some(Constant::F32(l / r)),
 +                BinOpKind::Rem => Some(Constant::F32(l % r)),
 +                BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                _ => None,
 +            },
 +            (Constant::F64(l), Some(Constant::F64(r))) => match op.node {
 +                BinOpKind::Add => Some(Constant::F64(l + r)),
 +                BinOpKind::Sub => Some(Constant::F64(l - r)),
 +                BinOpKind::Mul => Some(Constant::F64(l * r)),
 +                BinOpKind::Div => Some(Constant::F64(l / r)),
 +                BinOpKind::Rem => Some(Constant::F64(l % r)),
 +                BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                _ => None,
 +            },
 +            (l, r) => match (op.node, l, r) {
 +                (BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
 +                (BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
 +                (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
 +                    Some(r)
 +                },
 +                (BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
 +                (BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
 +                (BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
 +                _ => None,
 +            },
 +        }
 +    }
 +}
 +
 +pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
 +    use rustc_middle::mir::interpret::ConstValue;
 +    match result.val {
 +        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
 +            match result.ty.kind() {
 +                ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
 +                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
 +                ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
 +                    int.try_into().expect("invalid f32 bit representation"),
 +                ))),
 +                ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
 +                    int.try_into().expect("invalid f64 bit representation"),
 +                ))),
 +                ty::RawPtr(type_and_mut) => {
 +                    if let ty::Uint(_) = type_and_mut.ty.kind() {
 +                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
 +                    }
 +                    None
 +                },
 +                // FIXME: implement other conversions.
 +                _ => None,
 +            }
 +        },
 +        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
 +            ty::Ref(_, tam, _) => match tam.kind() {
 +                ty::Str => String::from_utf8(
 +                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
 +                        .to_owned(),
 +                )
 +                .ok()
 +                .map(Constant::Str),
 +                _ => None,
 +            },
 +            _ => None,
 +        },
 +        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
 +            ty::Array(sub_type, len) => match sub_type.kind() {
 +                ty::Float(FloatTy::F32) => match miri_to_const(len) {
 +                    Some(Constant::Int(len)) => alloc
 +                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
 +                        .to_owned()
 +                        .chunks(4)
 +                        .map(|chunk| {
 +                            Some(Constant::F32(f32::from_le_bytes(
 +                                chunk.try_into().expect("this shouldn't happen"),
 +                            )))
 +                        })
 +                        .collect::<Option<Vec<Constant>>>()
 +                        .map(Constant::Vec),
 +                    _ => None,
 +                },
 +                ty::Float(FloatTy::F64) => match miri_to_const(len) {
 +                    Some(Constant::Int(len)) => alloc
 +                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
 +                        .to_owned()
 +                        .chunks(8)
 +                        .map(|chunk| {
 +                            Some(Constant::F64(f64::from_le_bytes(
 +                                chunk.try_into().expect("this shouldn't happen"),
 +                            )))
 +                        })
 +                        .collect::<Option<Vec<Constant>>>()
 +                        .map(Constant::Vec),
 +                    _ => None,
 +                },
 +                // FIXME: implement other array type conversions.
 +                _ => None,
 +            },
 +            _ => None,
 +        },
 +        // FIXME: implement other conversions.
 +        _ => None,
 +    }
 +}
index 7e054a54c3c02c55dffa84ffe2aed159856d7616,0000000000000000000000000000000000000000..54d470ca738201c0a783cc6599de3bf42eb4c32b
mode 100644,000000..100644
--- /dev/null
@@@ -1,2224 -1,0 +1,2253 @@@
- #![feature(control_flow_enum)]
 +#![feature(box_patterns)]
++#![feature(control_flow_enum)]
 +#![feature(in_band_lifetimes)]
 +#![feature(let_else)]
++#![feature(once_cell)]
 +#![feature(rustc_private)]
- /// ```ignore
 +#![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_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +pub mod sym_helper;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
 +pub mod comparisons;
 +pub mod consts;
 +pub mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +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::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
++use std::lazy::SyncOnceCell;
++use std::sync::{Mutex, MutexGuard};
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
++use rustc_data_structures::fx::FxHashMap;
 +use rustc_data_structures::unhash::UnhashMap;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 +use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::itemlikevisit::ItemLikeVisitor;
 +use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 +use rustc_hir::{
 +    def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
 +    ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
 +    MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
 +    TraitItemKind, TraitRef, TyKind, UnOp,
 +};
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::exports::Export;
 +use rustc_middle::hir::map::Map;
 +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::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
 +use rustc_semver::RustcVersion;
 +use rustc_session::Session;
++use rustc_span::def_id::LocalDefId;
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::original_sp;
 +use rustc_span::sym;
 +use rustc_span::symbol::{kw, Symbol};
 +use rustc_span::{Span, DUMMY_SP};
 +use rustc_target::abi::Integer;
 +
 +use crate::consts::{constant, Constant};
 +use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
 +use crate::visitors::expr_visitor_no_bodies;
 +
 +pub 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!("`{}` is not a valid Rust version", msrv));
 +        }
 +    }
 +    None
 +}
 +
 +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
 +    msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
 +}
 +
 +#[macro_export]
 +macro_rules! extract_msrv_attr {
 +    (LateContext) => {
 +        extract_msrv_attr!(@LateContext, ());
 +    };
 +    (EarlyContext) => {
 +        extract_msrv_attr!(@EarlyContext);
 +    };
 +    (@$context:ident$(, $call:tt)?) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
 +            use $crate::get_unique_inner_attr;
 +            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
 +                Some(msrv_attr) => {
 +                    if let Some(msrv) = msrv_attr.value_str() {
 +                        self.msrv = $crate::parse_msrv(
 +                            &msrv.to_string(),
 +                            Some(cx.sess$($call)?),
 +                            Some(msrv_attr.span),
 +                        );
 +                    } else {
 +                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
 +                    }
 +                },
 +                _ => (),
 +            }
 +        }
 +    };
 +}
 +
++/// Returns `true` if the span comes from a macro expansion, no matter if from a
++/// macro by example or from a procedural macro
++#[must_use]
++pub fn in_macro(span: Span) -> bool {
++    span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
++}
++
 +/// Returns `true` if the two spans come from differing expansions (i.e., one is
 +/// from a macro and one isn't).
 +#[must_use]
 +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
 +    rhs.ctxt() != lhs.ctxt()
 +}
 +
 +/// 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:
- /// dbg!(def)
++/// ```
 +/// let abc = 1;
 +/// //        ^ output
 +/// let def = abc;
- /// dbg!(def)
++/// dbg!(def);
 +/// //   ^^^ input
 +///
 +/// // or...
 +/// let abc = 1;
 +/// let def = abc + 2;
 +/// //        ^^^^^^^ output
-         ExprKind::Call(repl_func, _) => if_chain! {
-             if let 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
-             }
-         },
++/// 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::Binding(pat)) = hir.find(hir_id);
 +        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
 +        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);
 +    match cx.tcx.hir().get(parent_id) {
 +        Node::Item(&Item {
 +            kind: ItemKind::Const(..) | ItemKind::Static(..),
 +            ..
 +        })
 +        | 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 `QPath` resolves to a constructor of a `LangItem`.
 +/// For example, use this to check whether a function call or a pattern is `Some(..)`.
 +pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool {
 +    if let QPath::Resolved(_, path) = qpath {
 +        if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
 +            if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
 +                return cx.tcx.parent(ctor_id) == Some(item_id);
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +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 first type parameter is a lang item.
 +pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| {
 +                cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
 +            })
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Checks if the first type parameter is a diagnostic item.
 +pub fn is_ty_param_diagnostic_item(
 +    cx: &LateContext<'_>,
 +    qpath: &QPath<'tcx>,
 +    item: Symbol,
 +) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// 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 get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
 +    match path {
 +        QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
 +        QPath::TypeRelative(_, s) => s.args,
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
 +    get_qpath_generics(path)
 +        .map_or([].as_ref(), |a| a.args)
 +        .iter()
 +        .filter_map(|a| {
 +            if let hir::GenericArg::Type(ty) = a {
 +                Some(ty)
 +            } else {
 +                None
 +            }
 +        })
 +}
 +
 +pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.get(0),
 +        QPath::TypeRelative(_, seg) => Some(seg),
 +        QPath::LangItem(..) => 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, resolve it. Otherwise, return `Res::Err`.
 +pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
 +    if let ExprKind::Path(p) = &expr.kind {
 +        cx.qpath_res(p, expr.hir_id)
 +    } else {
 +        Res::Err
 +    }
 +}
 +
 +/// Resolves the path to a `DefId` and checks if it matches the given path.
 +pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
 +    cx.qpath_res(path, hir_id)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 +///
 +/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
 +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
 +/// diagnostic item.
 +pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .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)
 +}
 +
 +/// Gets the definition associated to a path.
 +pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
 +    macro_rules! try_res {
 +        ($e:expr) => {
 +            match $e {
 +                Some(e) => e,
 +                None => return Res::Err,
 +            }
 +        };
 +    }
 +    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
 +        tcx.item_children(def_id)
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == name)
 +    }
 +
 +    let (krate, first, path) = match *path {
 +        [krate, first, ref path @ ..] => (krate, first, path),
 +        [primitive] => {
 +            return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
 +        },
 +        _ => return Res::Err,
 +    };
 +    let tcx = cx.tcx;
 +    let crates = tcx.crates(());
 +    let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
 +    let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
 +    let last = path
 +        .iter()
 +        .copied()
 +        // `get_def_path` seems to generate these empty segments for extern blocks.
 +        // We can just ignore them.
 +        .filter(|segment| !segment.is_empty())
 +        // for each segment, find the child item
 +        .try_fold(first, |item, segment| {
 +            let def_id = item.res.def_id();
 +            if let Some(item) = item_child_by_name(tcx, def_id, segment) {
 +                Some(item)
 +            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
 +                // it is not a child item so check inherent impl items
 +                tcx.inherent_impls(def_id)
 +                    .iter()
 +                    .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
 +            } else {
 +                None
 +            }
 +        });
 +    try_res!(last).res.expect_non_local()
 +}
 +
 +/// Convenience function to get the `DefId` of a trait by path.
 +/// It could be a trait or trait alias.
 +pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 +    match path_to_res(cx, path) {
 +        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>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != hir::CRATE_HIR_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
 +        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)
 +}
 +
 +/// 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;
 +    }
 +    for (x1, x2) in s1.iter().zip(s2.iter()) {
 +        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::String,
 +        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));
 +                }
 +            }
 +        }
 +    }
 +    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, y) => if_chain! {
 +            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
 +            if let LitKind::Int(v, _) = const_lit.node;
 +            if v <= 32 && is_default_equivalent(cx, x);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
- /// ```rust,ignore
++        ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func),
 +        ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
 +        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
 +        _ => 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(
 +    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(_)
 +        | ExprKind::LlvmInlineAsm(_) => 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<'tcx>, 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::Assign(_, 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(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 Visitor<'tcx> for V<'_, 'tcx> {
 +        type Map = ErasedMap<'tcx>;
 +        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +            NestedVisitorMap::None
 +        }
 +
 +        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).to_def_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(borrow) => match borrow.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(|| v.captures)
 +}
 +
 +/// 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>, Vec<&'tcx [Expr<'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, span, args, _) = &current.kind {
 +            if args.iter().any(|e| e.span.from_expansion()) {
 +                break;
 +            }
 +            method_names.push(path.ident.name);
 +            arg_lists.push(&**args);
 +            spans.push(*span);
 +            current = &args[0];
 +        } 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>]>> {
 +    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, _, args, _) = current.kind {
 +            if path.ident.name.as_str() == *method_name {
 +                if args.iter().any(|e| e.span.from_expansion()) {
 +                    return None;
 +                }
 +                matched.push(args); // build up `matched` backwards
 +                current = &args[0]; // 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);
 +    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
 +    Some(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);
 +    match cx.tcx.hir().find(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 {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_name(&mut self, _: Span, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// 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 {
 +    let mut found = false;
 +    expr_visitor_no_bodies(|expr| {
 +        if !found {
 +            if let hir::ExprKind::Ret(..) = &expr.kind {
 +                found = true;
 +            }
 +        }
 +        !found
 +    })
 +    .visit_expr(expr);
 +    found
 +}
 +
 +/// Finds calls of the specified macros in a function body.
 +pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
 +    let mut result = Vec::new();
 +    expr_visitor_no_bodies(|expr| {
 +        if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
 +            result.push(expr.span);
 +        }
 +        true
 +    })
 +    .visit_expr(&body.value);
 +    result
 +}
 +
 +/// Extends the span to the beginning of the spans line, incl. whitespaces.
 +///
- /// Returns the pre-expansion span if is this comes from an expansion of the
++/// ```rust
 +///        let x = ();
 +/// //             ^^
 +/// // will be converted to
 +///        let x = ();
 +/// // ^^^^^^^^^^^^^^
 +/// ```
 +fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    let span = original_sp(span, DUMMY_SP);
 +    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
 +    let line_no = source_map_and_line.line;
 +    let line_start = source_map_and_line.sf.lines[line_no];
 +    span.with_lo(line_start)
 +}
 +
 +/// 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_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
 +        match node {
 +            Node::Expr(
 +                e @ Expr {
 +                    kind: ExprKind::Loop(..) | ExprKind::Closure(..),
 +                    ..
 +                },
 +            ) => return Some(e),
 +            Node::Expr(_) | 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().local_def_id(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_typeck::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()
 +}
 +
- /// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
++/// 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
- /// ```rust,ignore
++/// # 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);
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    has_attr(attrs, sym::automatically_derived)
 +}
 +
 +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::SelfTy(..) = 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, None) = arm.pat.kind;
 +            if is_lang_ctor(cx, path, 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_lang_ctor(cx, path, 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
 +///
 +/// Useful for skipping long running code when it's unnecessary
 +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()
 +}
 +
 +#[allow(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
 +}
 +
 +#[allow(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 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);
 +    }
 +
 +    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);
 +/// ```
 +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
 +}
 +
 +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 +/// any.
 +///
 +/// Please use `match_any_diagnostic_items` 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 any of provided diagnostic items. Returns the index of
 +/// matching path, if any.
 +pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option<usize> {
 +    diag_items
 +        .iter()
 +        .position(|item| cx.tcx.is_diagnostic_item(*item, def_id))
 +}
 +
 +/// Checks if the given `DefId` matches the path.
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, 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)
 +}
 +
 +pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(func, [arg]) = expr.kind {
 +        expr_path_res(cx, func)
 +            .opt_def_id()
 +            .map_or(false, |id| match_panic_def_id(cx, id))
 +            .then(|| arg)
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
 +    match_any_def_paths(
 +        cx,
 +        did,
 +        &[
 +            &paths::BEGIN_PANIC,
 +            &paths::PANIC_ANY,
 +            &paths::PANICKING_PANIC,
 +            &paths::PANICKING_PANIC_FMT,
 +            &paths::PANICKING_PANIC_STR,
 +        ],
 +    )
 +    .is_some()
 +}
 +
 +/// 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 {
 +    matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
 +}
 +
 +/// Peels away all the compiler generated code surrounding the body of an async function,
 +pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(
 +        _,
 +        &[
 +            Expr {
 +                kind: ExprKind::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
 +}
 +
 +// Finds the `#[must_use]` attribute, if any
 +pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 +    attrs.iter().find(|a| a.has_name(sym::must_use))
 +}
 +
 +// 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| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 +}
 +
 +/// 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(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
 +        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
 +        _ => false,
 +    }
 +}
 +
 +/// Gets the node where an expression is either used, or it's type is unified with another branch.
 +pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
 +    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)),
 +            },
 +            Some((_, node)) => break Some(node),
 +        }
 +    }
 +}
 +
 +/// 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 attr, _) = attr.kind {
 +            attr.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 attr, _) = attr.kind {
 +            attr.path == sym::no_core
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
- struct VisitConstTestStruct<'tcx> {
++/// ```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(cx.tcx) { 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,
 +                ..
 +            },
 +            ..,
 +        ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
 +        _ => 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(cx.tcx).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(cx.tcx).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(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel(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(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(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)
 +}
 +
 +/// 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
 +}
 +
 +#[macro_export]
 +macro_rules! unwrap_cargo_metadata {
 +    ($cx: ident, $lint: ident, $deps: expr) => {{
 +        let mut command = cargo_metadata::MetadataCommand::new();
 +        if !$deps {
 +            command.no_deps();
 +        }
 +
 +        match command.exec() {
 +            Ok(metadata) => metadata,
 +            Err(err) => {
 +                span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
 +                return;
 +            },
 +        }
 +    }};
 +}
 +
 +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
 +}
 +
-     found: bool,
++struct TestItemNamesVisitor<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +    names: Vec<Symbol>,
- impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
 +}
-                 // and the `#[rustc_test_marker]` attribute?
++
++impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> {
 +    fn visit_item(&mut self, item: &Item<'_>) {
 +        if 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 has_test_marker && self.names.contains(&item.ident.name) {
-                         self.found = true;
 +                if let Res::Def(DefKind::Struct, _) = path.res {
 +                    let has_test_marker = self
 +                        .tcx
 +                        .hir()
 +                        .attrs(item.hir_id())
 +                        .iter()
 +                        .any(|a| a.has_name(sym::rustc_test_marker));
-     let names: Vec<_> = tcx
-         .hir()
-         .parent_iter(id)
-         // Since you can nest functions we need to collect all until we leave
-         // function scope
-         .filter_map(|(_id, node)| {
-             if let Node::Item(item) = node {
-                 if let ItemKind::Fn(_, _, _) = item.kind {
-                     return Some(item.ident.name);
++                    if has_test_marker {
++                        self.names.push(item.ident.name);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
 +    fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
 +    fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
 +}
 +
++static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
++
++fn with_test_item_names(tcx: TyCtxt<'tcx>, 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();
++    match map.entry(module) {
++        Entry::Occupied(entry) => f(entry.get()),
++        Entry::Vacant(entry) => {
++            let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
++            tcx.hir().visit_item_likes_in_module(module, &mut visitor);
++            visitor.names.sort_unstable();
++            f(&*entry.insert(visitor.names))
++        },
++    }
++}
++
 +/// Checks if the function containing the given `HirId` is a `#[test]` function
 +///
 +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
 +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
-             }
-             None
-         })
-         .collect();
-     let parent_mod = tcx.parent_module(id);
-     let mut vis = VisitConstTestStruct {
-         tcx,
-         names,
-         found: false,
-     };
-     tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
-     vis.found
++    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 whether item either has `test` attribute applied, or
 +/// is a module with `test` in its name.
 +///
 +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
 +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")
 +}
 +
 +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 cba96e05a2412244e6c36cd78d52b181c985cc8b,0000000000000000000000000000000000000000..03a9d3c25fd9862ac9efeaf616deba7fe6d34e2f
mode 100644,000000..100644
--- /dev/null
@@@ -1,230 -1,0 +1,325 @@@
- /// Returns index of the last camel-case component of `s`.
 +/// Dealing with sting indices can be hard, this struct ensures that both the
 +/// character and byte index are provided for correct indexing.
 +#[derive(Debug, Default, PartialEq, Eq)]
 +pub struct StrIndex {
 +    pub char_index: usize,
 +    pub byte_index: usize,
 +}
 +
 +impl StrIndex {
 +    pub fn new(char_index: usize, byte_index: usize) -> Self {
 +        Self { char_index, byte_index }
 +    }
 +}
 +
 +/// Returns the index of the character after the first camel-case component of `s`.
 +///
 +/// ```
++/// # use clippy_utils::str_utils::{camel_case_until, StrIndex};
 +/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
 +/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
 +/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
 +/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
 +/// ```
 +#[must_use]
 +pub fn camel_case_until(s: &str) -> StrIndex {
 +    let mut iter = s.char_indices().enumerate();
 +    if let Some((_char_index, (_, first))) = iter.next() {
 +        if !first.is_uppercase() {
 +            return StrIndex::new(0, 0);
 +        }
 +    } else {
 +        return StrIndex::new(0, 0);
 +    }
 +    let mut up = true;
 +    let mut last_index = StrIndex::new(0, 0);
 +    for (char_index, (byte_index, c)) in iter {
 +        if up {
 +            if c.is_lowercase() {
 +                up = false;
 +            } else {
 +                return last_index;
 +            }
 +        } else if c.is_uppercase() {
 +            up = true;
 +            last_index.byte_index = byte_index;
 +            last_index.char_index = char_index;
 +        } else if !c.is_lowercase() {
 +            return StrIndex::new(char_index, byte_index);
 +        }
 +    }
 +
 +    if up {
 +        last_index
 +    } else {
 +        StrIndex::new(s.chars().count(), s.len())
 +    }
 +}
 +
-     if let Some((char_index, (_, first))) = iter.next() {
++/// Returns index of the first camel-case component of `s`.
 +///
 +/// ```
++/// # use clippy_utils::str_utils::{camel_case_start, StrIndex};
 +/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
 +/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
 +/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
 +/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
 +/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
 +/// ```
 +#[must_use]
 +pub fn camel_case_start(s: &str) -> StrIndex {
++    camel_case_start_from_idx(s, 0)
++}
++
++/// Returns `StrIndex` of the last camel-case component of `s[idx..]`.
++///
++/// ```
++/// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex};
++/// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
++/// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
++/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0));
++/// assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3));
++/// assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7));
++/// ```
++pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex {
 +    let char_count = s.chars().count();
 +    let range = 0..char_count;
 +    let mut iter = range.rev().zip(s.char_indices().rev());
-             return StrIndex::new(char_index, s.len());
++    if let Some((_, (_, first))) = iter.next() {
 +        if !first.is_lowercase() {
++            return StrIndex::new(char_count, s.len());
 +        }
 +    } else {
 +        return StrIndex::new(char_count, s.len());
 +    }
++
 +    let mut down = true;
 +    let mut last_index = StrIndex::new(char_count, s.len());
 +    for (char_index, (byte_index, c)) in iter {
++        if byte_index < start_idx {
++            break;
++        }
 +        if down {
 +            if c.is_uppercase() {
 +                down = false;
 +                last_index.byte_index = byte_index;
 +                last_index.char_index = char_index;
 +            } else if !c.is_lowercase() {
 +                return last_index;
 +            }
 +        } else if c.is_lowercase() {
 +            down = true;
 +        } else if c.is_uppercase() {
 +            last_index.byte_index = byte_index;
 +            last_index.char_index = char_index;
 +        } else {
 +            return last_index;
 +        }
 +    }
++
 +    last_index
 +}
 +
++/// Get the indexes of camel case components of a string `s`
++///
++/// ```
++/// # use clippy_utils::str_utils::{camel_case_indices, StrIndex};
++/// assert_eq!(
++///     camel_case_indices("AbcDef"),
++///     vec![StrIndex::new(0, 0), StrIndex::new(3, 3), StrIndex::new(6, 6)]
++/// );
++/// assert_eq!(
++///     camel_case_indices("abcDef"),
++///     vec![StrIndex::new(3, 3), StrIndex::new(6, 6)]
++/// );
++/// ```
++pub fn camel_case_indices(s: &str) -> Vec<StrIndex> {
++    let mut result = Vec::new();
++    let mut str_idx = camel_case_start(s);
++
++    while str_idx.byte_index < s.len() {
++        let next_idx = str_idx.byte_index + 1;
++        result.push(str_idx);
++        str_idx = camel_case_start_from_idx(s, next_idx);
++    }
++    result.push(str_idx);
++
++    result
++}
++
++/// Split camel case string into a vector of its components
++///
++/// ```
++/// # use clippy_utils::str_utils::{camel_case_split, StrIndex};
++/// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
++/// ```
++pub fn camel_case_split(s: &str) -> Vec<&str> {
++    let mut offsets = camel_case_indices(s)
++        .iter()
++        .map(|e| e.byte_index)
++        .collect::<Vec<usize>>();
++    if offsets[0] != 0 {
++        offsets.insert(0, 0);
++    }
++
++    offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect()
++}
++
 +/// Dealing with sting comparison can be complicated, this struct ensures that both the
 +/// character and byte count are provided for correct indexing.
 +#[derive(Debug, Default, PartialEq, Eq)]
 +pub struct StrCount {
 +    pub char_count: usize,
 +    pub byte_count: usize,
 +}
 +
 +impl StrCount {
 +    pub fn new(char_count: usize, byte_count: usize) -> Self {
 +        Self { char_count, byte_count }
 +    }
 +}
 +
 +/// Returns the number of chars that match from the start
 +///
 +/// ```
++/// # use clippy_utils::str_utils::{count_match_start, StrCount};
 +/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
 +/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
 +/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
 +/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
 +/// ```
 +#[must_use]
 +pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
 +    // (char_index, char1)
 +    let char_count = str1.chars().count();
 +    let iter1 = (0..=char_count).zip(str1.chars());
 +    // (byte_index, char2)
 +    let iter2 = str2.char_indices();
 +
 +    iter1
 +        .zip(iter2)
 +        .take_while(|((_, c1), (_, c2))| c1 == c2)
 +        .last()
 +        .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
 +            StrCount::new(char_index + 1, byte_index + character.len_utf8())
 +        })
 +}
 +
 +/// Returns the number of chars and bytes that match from the end
 +///
 +/// ```
++/// # use clippy_utils::str_utils::{count_match_end, StrCount};
 +/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
 +/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
 +/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
 +/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
 +/// ```
 +#[must_use]
 +pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
 +    let char_count = str1.chars().count();
 +    if char_count == 0 {
 +        return StrCount::default();
 +    }
 +
 +    // (char_index, char1)
 +    let iter1 = (0..char_count).rev().zip(str1.chars().rev());
 +    // (byte_index, char2)
 +    let byte_count = str2.len();
 +    let iter2 = str2.char_indices().rev();
 +
 +    iter1
 +        .zip(iter2)
 +        .take_while(|((_, c1), (_, c2))| c1 == c2)
 +        .last()
 +        .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
 +            StrCount::new(char_count - char_index, byte_count - byte_index)
 +        })
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +
 +    #[test]
 +    fn camel_case_start_full() {
 +        assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
 +        assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
 +        assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
 +        assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
 +        assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
 +    }
 +
 +    #[test]
 +    fn camel_case_start_partial() {
 +        assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
 +        assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
 +        assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
 +        assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
 +    }
 +
 +    #[test]
 +    fn camel_case_start_not() {
 +        assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
 +        assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
 +        assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
 +        assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
 +    }
 +
 +    #[test]
 +    fn camel_case_start_caps() {
 +        assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
 +    }
 +
 +    #[test]
 +    fn camel_case_until_full() {
 +        assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
 +        assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
 +        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
 +    }
 +
 +    #[test]
 +    fn camel_case_until_not() {
 +        assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
 +        assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
 +    }
 +
 +    #[test]
 +    fn camel_case_until_partial() {
 +        assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
 +        assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
 +        assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
 +        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
 +    }
 +
 +    #[test]
 +    fn until_caps() {
 +        assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
 +    }
++
++    #[test]
++    fn camel_case_start_from_idx_full() {
++        assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
++        assert_eq!(camel_case_start_from_idx("AbcDef", 4), StrIndex::new(6, 6));
++        assert_eq!(camel_case_start_from_idx("AbcDefGhi", 0), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start_from_idx("AbcDefGhi", 1), StrIndex::new(3, 3));
++        assert_eq!(camel_case_start_from_idx("Abcdefg", 1), StrIndex::new(7, 7));
++    }
++
++    #[test]
++    fn camel_case_indices_full() {
++        assert_eq!(camel_case_indices("Abc\u{f6}\u{f6}DD"), vec![StrIndex::new(7, 9)]);
++    }
++
++    #[test]
++    fn camel_case_split_full() {
++        assert_eq!(camel_case_split("A"), vec!["A"]);
++        assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
++        assert_eq!(camel_case_split("Abc"), vec!["Abc"]);
++        assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]);
++        assert_eq!(
++            camel_case_split("\u{f6}\u{f6}AabABcd"),
++            vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"]
++        );
++    }
 +}
index 586934df46037a3609de57bdfa0307e0ba619142,0000000000000000000000000000000000000000..92662c59226a2e300f38ac8378fe9f932540ce98
mode 100644,000000..100644
--- /dev/null
@@@ -1,1016 -1,0 +1,1091 @@@
- use crate::source::{
-     snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
- };
 +//! Contains utility functions to generate suggestions.
 +#![deny(clippy::missing_docs_in_private_items)]
 +
-     BinOp(AssocOp, Cow<'a, str>),
++use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite};
 +use crate::{get_parent_expr_for_hir, higher};
 +use rustc_ast::util::parser::AssocOp;
 +use rustc_ast::{ast, token};
 +use rustc_ast_pretty::pprust::token_kind_to_string;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::{ExprKind, HirId, MutTy, TyKind};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{EarlyContext, LateContext, LintContext};
 +use rustc_middle::hir::place::ProjectionKind;
 +use rustc_middle::mir::{FakeReadCause, Mutability};
 +use rustc_middle::ty;
 +use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
 +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 +use std::borrow::Cow;
 +use std::convert::TryInto;
 +use std::fmt::Display;
 +use std::iter;
 +use std::ops::{Add, Neg, Not, Sub};
 +
 +/// A helper type to build suggestion correctly handling parentheses.
 +#[derive(Clone, PartialEq)]
 +pub enum Sugg<'a> {
 +    /// An expression that never needs parentheses such as `1337` or `[0; 42]`.
 +    NonParen(Cow<'a, str>),
 +    /// An expression that does not fit in other variants.
 +    MaybeParen(Cow<'a, str>),
 +    /// A binary operator expression, including `as`-casts and explicit type
 +    /// coercion.
-             Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => s.fmt(f),
++    BinOp(AssocOp, Cow<'a, str>, Cow<'a, str>),
 +}
 +
 +/// Literal constant `0`, for convenience.
 +pub const ZERO: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("0"));
 +/// Literal constant `1`, for convenience.
 +pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1"));
 +/// a constant represents an empty string, for convenience.
 +pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));
 +
 +impl Display for Sugg<'_> {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
 +        match *self {
-         snippet_opt(cx, expr.span).map(|snippet| {
-             let snippet = Cow::Owned(snippet);
-             Self::hir_from_snippet(expr, snippet)
-         })
++            Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) => s.fmt(f),
++            Sugg::BinOp(op, ref lhs, ref rhs) => binop_to_string(op, lhs, rhs).fmt(f),
 +        }
 +    }
 +}
 +
 +#[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method
 +impl<'a> Sugg<'a> {
 +    /// Prepare a suggestion from an expression.
 +    pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
-         let snippet = snippet_with_macro_callsite(cx, expr.span, default);
-         Self::hir_from_snippet(expr, snippet)
++        let get_snippet = |span| snippet(cx, span, "");
++        snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(expr, get_snippet))
 +    }
 +
 +    /// Convenience function around `hir_opt` for suggestions with a default
 +    /// text.
 +    pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
 +        Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default)))
 +    }
 +
 +    /// Same as `hir`, but it adapts the applicability level by following rules:
 +    ///
 +    /// - Applicability level `Unspecified` will never be changed.
 +    /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 +    /// - If the default value is used and the applicability level is `MachineApplicable`, change it
 +    ///   to
 +    /// `HasPlaceholders`
 +    pub fn hir_with_applicability(
 +        cx: &LateContext<'_>,
 +        expr: &hir::Expr<'_>,
 +        default: &'a str,
 +        applicability: &mut Applicability,
 +    ) -> Self {
 +        if *applicability != Applicability::Unspecified && expr.span.from_expansion() {
 +            *applicability = Applicability::MaybeIncorrect;
 +        }
 +        Self::hir_opt(cx, expr).unwrap_or_else(|| {
 +            if *applicability == Applicability::MachineApplicable {
 +                *applicability = Applicability::HasPlaceholders;
 +            }
 +            Sugg::NonParen(Cow::Borrowed(default))
 +        })
 +    }
 +
 +    /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
 +    pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
-         let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
-         if in_macro {
-             Sugg::NonParen(snippet)
++        let get_snippet = |span| snippet_with_macro_callsite(cx, span, default);
++        Self::hir_from_snippet(expr, get_snippet)
 +    }
 +
 +    /// Same as `hir`, but first walks the span up to the given context. This will result in the
 +    /// macro call, rather then the expansion, if the span is from a child context. If the span is
 +    /// not from a child context, it will be used directly instead.
 +    ///
 +    /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
 +    /// node would result in `box []`. If given the context of the address of expression, this
 +    /// function will correctly get a snippet of `vec![]`.
 +    pub fn hir_with_context(
 +        cx: &LateContext<'_>,
 +        expr: &hir::Expr<'_>,
 +        ctxt: SyntaxContext,
 +        default: &'a str,
 +        applicability: &mut Applicability,
 +    ) -> Self {
-             Self::hir_from_snippet(expr, snippet)
++        if expr.span.ctxt() == ctxt {
++            Self::hir_from_snippet(expr, |span| snippet(cx, span, default))
 +        } else {
-     fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
++            let snip = snippet_with_applicability(cx, expr.span, default, applicability);
++            Sugg::NonParen(snip)
 +        }
 +    }
 +
 +    /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
 +    /// function variants of `Sugg`, since these use different snippet functions.
-             return Sugg::BinOp(op, snippet);
++    fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a, str>) -> Self {
 +        if let Some(range) = higher::Range::hir(expr) {
 +            let op = match range.limits {
 +                ast::RangeLimits::HalfOpen => AssocOp::DotDot,
 +                ast::RangeLimits::Closed => AssocOp::DotDotEq,
 +            };
-             | hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
++            let start = range.start.map_or("".into(), |expr| get_snippet(expr.span));
++            let end = range.end.map_or("".into(), |expr| get_snippet(expr.span));
++
++            return Sugg::BinOp(op, start, end);
 +        }
 +
 +        match expr.kind {
 +            hir::ExprKind::AddrOf(..)
 +            | hir::ExprKind::Box(..)
 +            | hir::ExprKind::If(..)
 +            | hir::ExprKind::Let(..)
 +            | hir::ExprKind::Closure(..)
 +            | hir::ExprKind::Unary(..)
-             | hir::ExprKind::Err => Sugg::NonParen(snippet),
-             hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
-             hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
-             hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node.into()), snippet),
-             hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
-             hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
++            | hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)),
 +            hir::ExprKind::Continue(..)
 +            | hir::ExprKind::Yield(..)
 +            | hir::ExprKind::Array(..)
 +            | hir::ExprKind::Block(..)
 +            | hir::ExprKind::Break(..)
 +            | hir::ExprKind::Call(..)
 +            | hir::ExprKind::Field(..)
 +            | hir::ExprKind::Index(..)
 +            | hir::ExprKind::InlineAsm(..)
 +            | hir::ExprKind::LlvmInlineAsm(..)
 +            | hir::ExprKind::ConstBlock(..)
 +            | hir::ExprKind::Lit(..)
 +            | hir::ExprKind::Loop(..)
 +            | hir::ExprKind::MethodCall(..)
 +            | hir::ExprKind::Path(..)
 +            | hir::ExprKind::Repeat(..)
 +            | hir::ExprKind::Ret(..)
 +            | hir::ExprKind::Struct(..)
 +            | hir::ExprKind::Tup(..)
 +            | hir::ExprKind::DropTemps(_)
-         let snippet = if expr.span.from_expansion() {
-             snippet_with_macro_callsite(cx, expr.span, default)
-         } else {
-             snippet(cx, expr.span, default)
++            | hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
++            hir::ExprKind::Assign(lhs, rhs, _) => {
++                Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
++            },
++            hir::ExprKind::AssignOp(op, lhs, rhs) => {
++                Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span))
++            },
++            hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
++                AssocOp::from_ast_binop(op.node.into()),
++                get_snippet(lhs.span),
++                get_snippet(rhs.span),
++            ),
++            hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
++            hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Colon, get_snippet(lhs.span), get_snippet(ty.span)),
 +        }
 +    }
 +
 +    /// Prepare a suggestion from an expression.
 +    pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
 +        use rustc_ast::ast::RangeLimits;
 +
-             | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
++        let get_whole_snippet = || {
++            if expr.span.from_expansion() {
++                snippet_with_macro_callsite(cx, expr.span, default)
++            } else {
++                snippet(cx, expr.span, default)
++            }
 +        };
 +
 +        match expr.kind {
 +            ast::ExprKind::AddrOf(..)
 +            | ast::ExprKind::Box(..)
 +            | ast::ExprKind::Closure(..)
 +            | ast::ExprKind::If(..)
 +            | ast::ExprKind::Let(..)
 +            | ast::ExprKind::Unary(..)
-             | ast::ExprKind::Err => Sugg::NonParen(snippet),
-             ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
-             ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet),
-             ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
-             ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
-             ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
-             ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
-             ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
++            | ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()),
 +            ast::ExprKind::Async(..)
 +            | ast::ExprKind::Block(..)
 +            | ast::ExprKind::Break(..)
 +            | ast::ExprKind::Call(..)
 +            | ast::ExprKind::Continue(..)
 +            | ast::ExprKind::Yield(..)
 +            | ast::ExprKind::Field(..)
 +            | ast::ExprKind::ForLoop(..)
 +            | ast::ExprKind::Index(..)
 +            | ast::ExprKind::InlineAsm(..)
 +            | ast::ExprKind::LlvmInlineAsm(..)
 +            | ast::ExprKind::ConstBlock(..)
 +            | ast::ExprKind::Lit(..)
 +            | ast::ExprKind::Loop(..)
 +            | ast::ExprKind::MacCall(..)
 +            | ast::ExprKind::MethodCall(..)
 +            | ast::ExprKind::Paren(..)
 +            | ast::ExprKind::Underscore
 +            | ast::ExprKind::Path(..)
 +            | ast::ExprKind::Repeat(..)
 +            | ast::ExprKind::Ret(..)
 +            | ast::ExprKind::Struct(..)
 +            | ast::ExprKind::Try(..)
 +            | ast::ExprKind::TryBlock(..)
 +            | ast::ExprKind::Tup(..)
 +            | ast::ExprKind::Array(..)
 +            | ast::ExprKind::While(..)
 +            | ast::ExprKind::Await(..)
-             Sugg::BinOp(_, sugg) => {
-                 if has_enclosing_paren(&sugg) {
-                     Sugg::NonParen(sugg)
-                 } else {
-                     Sugg::NonParen(format!("({})", sugg).into())
-                 }
++            | ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()),
++            ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
++                AssocOp::DotDot,
++                lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
++                rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
++            ),
++            ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
++                AssocOp::DotDotEq,
++                lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
++                rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
++            ),
++            ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
++                AssocOp::Assign,
++                snippet(cx, lhs.span, default),
++                snippet(cx, rhs.span, default),
++            ),
++            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
++                astbinop2assignop(op),
++                snippet(cx, lhs.span, default),
++                snippet(cx, rhs.span, default),
++            ),
++            ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
++                AssocOp::from_ast_binop(op.node),
++                snippet(cx, lhs.span, default),
++                snippet(cx, rhs.span, default),
++            ),
++            ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
++                AssocOp::As,
++                snippet(cx, lhs.span, default),
++                snippet(cx, ty.span, default),
++            ),
++            ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
++                AssocOp::Colon,
++                snippet(cx, lhs.span, default),
++                snippet(cx, ty.span, default),
++            ),
 +        }
 +    }
 +
 +    /// Convenience method to create the `<lhs> && <rhs>` suggestion.
 +    pub fn and(self, rhs: &Self) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::And, &self, rhs)
 +    }
 +
 +    /// Convenience method to create the `<lhs> & <rhs>` suggestion.
 +    pub fn bit_and(self, rhs: &Self) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::BitAnd, &self, rhs)
 +    }
 +
 +    /// Convenience method to create the `<lhs> as <rhs>` suggestion.
 +    pub fn as_ty<R: Display>(self, rhs: R) -> Sugg<'static> {
 +        make_assoc(AssocOp::As, &self, &Sugg::NonParen(rhs.to_string().into()))
 +    }
 +
 +    /// Convenience method to create the `&<expr>` suggestion.
 +    pub fn addr(self) -> Sugg<'static> {
 +        make_unop("&", self)
 +    }
 +
 +    /// Convenience method to create the `&mut <expr>` suggestion.
 +    pub fn mut_addr(self) -> Sugg<'static> {
 +        make_unop("&mut ", self)
 +    }
 +
 +    /// Convenience method to create the `*<expr>` suggestion.
 +    pub fn deref(self) -> Sugg<'static> {
 +        make_unop("*", self)
 +    }
 +
 +    /// Convenience method to create the `&*<expr>` suggestion. Currently this
 +    /// is needed because `sugg.deref().addr()` produces an unnecessary set of
 +    /// parentheses around the deref.
 +    pub fn addr_deref(self) -> Sugg<'static> {
 +        make_unop("&*", self)
 +    }
 +
 +    /// Convenience method to create the `&mut *<expr>` suggestion. Currently
 +    /// this is needed because `sugg.deref().mut_addr()` produces an unnecessary
 +    /// set of parentheses around the deref.
 +    pub fn mut_addr_deref(self) -> Sugg<'static> {
 +        make_unop("&mut *", self)
 +    }
 +
 +    /// Convenience method to transform suggestion into a return call
 +    pub fn make_return(self) -> Sugg<'static> {
 +        Sugg::NonParen(Cow::Owned(format!("return {}", self)))
 +    }
 +
 +    /// Convenience method to transform suggestion into a block
 +    /// where the suggestion is a trailing expression
 +    pub fn blockify(self) -> Sugg<'static> {
 +        Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
 +    }
 +
 +    /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
 +    /// suggestion.
 +    #[allow(dead_code)]
 +    pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
 +        match limit {
 +            ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end),
 +            ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, end),
 +        }
 +    }
 +
 +    /// Adds parentheses to any expression that might need them. Suitable to the
 +    /// `self` argument of a method call
 +    /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
 +    #[must_use]
 +    pub fn maybe_par(self) -> Self {
 +        match self {
 +            Sugg::NonParen(..) => self,
 +            // `(x)` and `(x).y()` both don't need additional parens.
 +            Sugg::MaybeParen(sugg) => {
 +                if has_enclosing_paren(&sugg) {
 +                    Sugg::MaybeParen(sugg)
 +                } else {
 +                    Sugg::NonParen(format!("({})", sugg).into())
 +                }
 +            },
- impl Not for Sugg<'_> {
-     type Output = Sugg<'static>;
-     fn not(self) -> Sugg<'static> {
-         make_unop("!", self)
++            Sugg::BinOp(op, lhs, rhs) => {
++                let sugg = binop_to_string(op, &lhs, &rhs);
++                Sugg::NonParen(format!("({})", sugg).into())
 +            },
 +        }
 +    }
 +}
 +
++/// Generates a string from the operator and both sides.
++fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
++    match op {
++        AssocOp::Add
++        | AssocOp::Subtract
++        | AssocOp::Multiply
++        | AssocOp::Divide
++        | AssocOp::Modulus
++        | AssocOp::LAnd
++        | AssocOp::LOr
++        | AssocOp::BitXor
++        | AssocOp::BitAnd
++        | AssocOp::BitOr
++        | AssocOp::ShiftLeft
++        | AssocOp::ShiftRight
++        | AssocOp::Equal
++        | AssocOp::Less
++        | AssocOp::LessEqual
++        | AssocOp::NotEqual
++        | AssocOp::Greater
++        | AssocOp::GreaterEqual => format!(
++            "{} {} {}",
++            lhs,
++            op.to_ast_binop().expect("Those are AST ops").to_string(),
++            rhs
++        ),
++        AssocOp::Assign => format!("{} = {}", lhs, rhs),
++        AssocOp::AssignOp(op) => {
++            format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
++        },
++        AssocOp::As => format!("{} as {}", lhs, rhs),
++        AssocOp::DotDot => format!("{}..{}", lhs, rhs),
++        AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
++        AssocOp::Colon => format!("{}: {}", lhs, rhs),
++    }
++}
++
 +/// Return `true` if `sugg` is enclosed in parenthesis.
 +fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
 +    let mut chars = sugg.as_ref().chars();
 +    if chars.next() == Some('(') {
 +        let mut depth = 1;
 +        for c in &mut chars {
 +            if c == '(' {
 +                depth += 1;
 +            } else if c == ')' {
 +                depth -= 1;
 +            }
 +            if depth == 0 {
 +                break;
 +            }
 +        }
 +        chars.next().is_none()
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Copied from the rust standard library, and then edited
 +macro_rules! forward_binop_impls_to_ref {
 +    (impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => {
 +        impl $imp<$t> for &$t {
 +            type Output = $o;
 +
 +            fn $method(self, other: $t) -> $o {
 +                $imp::$method(self, &other)
 +            }
 +        }
 +
 +        impl $imp<&$t> for $t {
 +            type Output = $o;
 +
 +            fn $method(self, other: &$t) -> $o {
 +                $imp::$method(&self, other)
 +            }
 +        }
 +
 +        impl $imp for $t {
 +            type Output = $o;
 +
 +            fn $method(self, other: $t) -> $o {
 +                $imp::$method(&self, &other)
 +            }
 +        }
 +    };
 +}
 +
 +impl Add for &Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::Add, self, rhs)
 +    }
 +}
 +
 +impl Sub for &Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::Sub, self, rhs)
 +    }
 +}
 +
 +forward_binop_impls_to_ref!(impl Add, add for Sugg<'_>, type Output = Sugg<'static>);
 +forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'static>);
 +
 +impl Neg for Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn neg(self) -> Sugg<'static> {
 +        make_unop("-", self)
 +    }
 +}
 +
-     let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
++impl Not for Sugg<'a> {
++    type Output = Sugg<'a>;
++    fn not(self) -> Sugg<'a> {
++        use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual};
++
++        if let Sugg::BinOp(op, lhs, rhs) = self {
++            let to_op = match op {
++                Equal => NotEqual,
++                NotEqual => Equal,
++                Less => GreaterEqual,
++                GreaterEqual => Less,
++                Greater => LessEqual,
++                LessEqual => Greater,
++                _ => return make_unop("!", Sugg::BinOp(op, lhs, rhs)),
++            };
++            Sugg::BinOp(to_op, lhs, rhs)
++        } else {
++            make_unop("!", self)
++        }
 +    }
 +}
 +
 +/// Helper type to display either `foo` or `(foo)`.
 +struct ParenHelper<T> {
 +    /// `true` if parentheses are needed.
 +    paren: bool,
 +    /// The main thing to display.
 +    wrapped: T,
 +}
 +
 +impl<T> ParenHelper<T> {
 +    /// Builds a `ParenHelper`.
 +    fn new(paren: bool, wrapped: T) -> Self {
 +        Self { paren, wrapped }
 +    }
 +}
 +
 +impl<T: Display> Display for ParenHelper<T> {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
 +        if self.paren {
 +            write!(f, "({})", self.wrapped)
 +        } else {
 +            self.wrapped.fmt(f)
 +        }
 +    }
 +}
 +
 +/// Builds the string for `<op><expr>` adding parenthesis when necessary.
 +///
 +/// For convenience, the operator is taken as a string because all unary
 +/// operators have the same
 +/// precedence.
 +pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
 +    Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into())
 +}
 +
 +/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
 +///
 +/// Precedence of shift operator relative to other arithmetic operation is
 +/// often confusing so
 +/// parenthesis will always be added for a mix of these.
 +pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
 +    /// Returns `true` if the operator is a shift operator `<<` or `>>`.
 +    fn is_shift(op: AssocOp) -> bool {
 +        matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
 +    }
 +
 +    /// Returns `true` if the operator is an arithmetic operator
 +    /// (i.e., `+`, `-`, `*`, `/`, `%`).
 +    fn is_arith(op: AssocOp) -> bool {
 +        matches!(
 +            op,
 +            AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
 +        )
 +    }
 +
 +    /// Returns `true` if the operator `op` needs parenthesis with the operator
 +    /// `other` in the direction `dir`.
 +    fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool {
 +        other.precedence() < op.precedence()
 +            || (other.precedence() == op.precedence()
 +                && ((op != other && associativity(op) != dir)
 +                    || (op == other && associativity(op) != Associativity::Both)))
 +            || is_shift(op) && is_arith(other)
 +            || is_shift(other) && is_arith(op)
 +    }
 +
-     let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
++    let lhs_paren = if let Sugg::BinOp(lop, _, _) = *lhs {
 +        needs_paren(op, lop, Associativity::Left)
 +    } else {
 +        false
 +    };
 +
-     let lhs = ParenHelper::new(lhs_paren, lhs);
-     let rhs = ParenHelper::new(rhs_paren, rhs);
-     let sugg = match op {
-         AssocOp::Add
-         | AssocOp::BitAnd
-         | AssocOp::BitOr
-         | AssocOp::BitXor
-         | AssocOp::Divide
-         | AssocOp::Equal
-         | AssocOp::Greater
-         | AssocOp::GreaterEqual
-         | AssocOp::LAnd
-         | AssocOp::LOr
-         | AssocOp::Less
-         | AssocOp::LessEqual
-         | AssocOp::Modulus
-         | AssocOp::Multiply
-         | AssocOp::NotEqual
-         | AssocOp::ShiftLeft
-         | AssocOp::ShiftRight
-         | AssocOp::Subtract => format!(
-             "{} {} {}",
-             lhs,
-             op.to_ast_binop().expect("Those are AST ops").to_string(),
-             rhs
-         ),
-         AssocOp::Assign => format!("{} = {}", lhs, rhs),
-         AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs),
-         AssocOp::As => format!("{} as {}", lhs, rhs),
-         AssocOp::DotDot => format!("{}..{}", lhs, rhs),
-         AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
-         AssocOp::Colon => format!("{}: {}", lhs, rhs),
-     };
-     Sugg::BinOp(op, sugg.into())
++    let rhs_paren = if let Sugg::BinOp(rop, _, _) = *rhs {
 +        needs_paren(op, rop, Associativity::Right)
 +    } else {
 +        false
 +    };
 +
-         let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into());
++    let lhs = ParenHelper::new(lhs_paren, lhs).to_string();
++    let rhs = ParenHelper::new(rhs_paren, rhs).to_string();
++    Sugg::BinOp(op, lhs.into(), rhs.into())
 +}
 +
 +/// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`.
 +pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
 +    make_assoc(AssocOp::from_ast_binop(op), lhs, rhs)
 +}
 +
 +#[derive(PartialEq, Eq, Clone, Copy)]
 +/// Operator associativity.
 +enum Associativity {
 +    /// The operator is both left-associative and right-associative.
 +    Both,
 +    /// The operator is left-associative.
 +    Left,
 +    /// The operator is not associative.
 +    None,
 +    /// The operator is right-associative.
 +    Right,
 +}
 +
 +/// Returns the associativity/fixity of an operator. The difference with
 +/// `AssocOp::fixity` is that an operator can be both left and right associative
 +/// (such as `+`: `a + b + c == (a + b) + c == a + (b + c)`.
 +///
 +/// Chained `as` and explicit `:` type coercion never need inner parenthesis so
 +/// they are considered
 +/// associative.
 +#[must_use]
 +fn associativity(op: AssocOp) -> Associativity {
 +    use rustc_ast::util::parser::AssocOp::{
 +        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater,
 +        GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
 +    };
 +
 +    match op {
 +        Assign | AssignOp(_) => Associativity::Right,
 +        Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
 +        Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
 +        | Subtract => Associativity::Left,
 +        DotDot | DotDotEq => Associativity::None,
 +    }
 +}
 +
 +/// Converts a `hir::BinOp` to the corresponding assigning binary operator.
 +fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
 +    use rustc_ast::token::BinOpToken::{And, Caret, Minus, Or, Percent, Plus, Shl, Shr, Slash, Star};
 +
 +    AssocOp::AssignOp(match op.node {
 +        hir::BinOpKind::Add => Plus,
 +        hir::BinOpKind::BitAnd => And,
 +        hir::BinOpKind::BitOr => Or,
 +        hir::BinOpKind::BitXor => Caret,
 +        hir::BinOpKind::Div => Slash,
 +        hir::BinOpKind::Mul => Star,
 +        hir::BinOpKind::Rem => Percent,
 +        hir::BinOpKind::Shl => Shl,
 +        hir::BinOpKind::Shr => Shr,
 +        hir::BinOpKind::Sub => Minus,
 +
 +        hir::BinOpKind::And
 +        | hir::BinOpKind::Eq
 +        | hir::BinOpKind::Ge
 +        | hir::BinOpKind::Gt
 +        | hir::BinOpKind::Le
 +        | hir::BinOpKind::Lt
 +        | hir::BinOpKind::Ne
 +        | hir::BinOpKind::Or => panic!("This operator does not exist"),
 +    })
 +}
 +
 +/// Converts an `ast::BinOp` to the corresponding assigning binary operator.
 +fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
 +    use rustc_ast::ast::BinOpKind::{
 +        Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
 +    };
 +    use rustc_ast::token::BinOpToken;
 +
 +    AssocOp::AssignOp(match op.node {
 +        Add => BinOpToken::Plus,
 +        BitAnd => BinOpToken::And,
 +        BitOr => BinOpToken::Or,
 +        BitXor => BinOpToken::Caret,
 +        Div => BinOpToken::Slash,
 +        Mul => BinOpToken::Star,
 +        Rem => BinOpToken::Percent,
 +        Shl => BinOpToken::Shl,
 +        Shr => BinOpToken::Shr,
 +        Sub => BinOpToken::Minus,
 +        And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"),
 +    })
 +}
 +
 +/// Returns the indentation before `span` if there are nothing but `[ \t]`
 +/// before it on its line.
 +fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 +    let lo = cx.sess().source_map().lookup_char_pos(span.lo());
 +    lo.file
 +        .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */)
 +        .and_then(|line| {
 +            if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
 +                // We can mix char and byte positions here because we only consider `[ \t]`.
 +                if lo.col == CharPos(pos) {
 +                    Some(line[..pos].into())
 +                } else {
 +                    None
 +                }
 +            } else {
 +                None
 +            }
 +        })
 +}
 +
 +/// Convenience extension trait for `DiagnosticBuilder`.
 +pub trait DiagnosticBuilderExt<T: LintContext> {
 +    /// Suggests to add an attribute to an item.
 +    ///
 +    /// Correctly handles indentation of the attribute and item.
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_item_with_attr(cx, item, "#[derive(Default)]");
 +    /// ```
 +    fn suggest_item_with_attr<D: Display + ?Sized>(
 +        &mut self,
 +        cx: &T,
 +        item: Span,
 +        msg: &str,
 +        attr: &D,
 +        applicability: Applicability,
 +    );
 +
 +    /// Suggest to add an item before another.
 +    ///
 +    /// The item should not be indented (except for inner indentation).
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_prepend_item(cx, item,
 +    /// "fn foo() {
 +    ///     bar();
 +    /// }");
 +    /// ```
 +    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability);
 +
 +    /// Suggest to completely remove an item.
 +    ///
 +    /// This will remove an item and all following whitespace until the next non-whitespace
 +    /// character. This should work correctly if item is on the same indentation level as the
 +    /// following item.
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_remove_item(cx, item, "remove this")
 +    /// ```
 +    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
 +}
 +
 +impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> {
 +    fn suggest_item_with_attr<D: Display + ?Sized>(
 +        &mut self,
 +        cx: &T,
 +        item: Span,
 +        msg: &str,
 +        attr: &D,
 +        applicability: Applicability,
 +    ) {
 +        if let Some(indent) = indentation(cx, item) {
 +            let span = item.with_hi(item.lo());
 +
 +            self.span_suggestion(span, msg, format!("{}\n{}", attr, indent), applicability);
 +        }
 +    }
 +
 +    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability) {
 +        if let Some(indent) = indentation(cx, item) {
 +            let span = item.with_hi(item.lo());
 +
 +            let mut first = true;
 +            let new_item = new_item
 +                .lines()
 +                .map(|l| {
 +                    if first {
 +                        first = false;
 +                        format!("{}\n", l)
 +                    } else {
 +                        format!("{}{}\n", indent, l)
 +                    }
 +                })
 +                .collect::<String>();
 +
 +            self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent), applicability);
 +        }
 +    }
 +
 +    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability) {
 +        let mut remove_span = item;
 +        let hi = cx.sess().source_map().next_point(remove_span).hi();
 +        let fmpos = cx.sess().source_map().lookup_byte_offset(hi);
 +
 +        if let Some(ref src) = fmpos.sf.src {
 +            let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
 +
 +            if let Some(non_whitespace_offset) = non_whitespace_offset {
 +                remove_span = remove_span
 +                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
 +            }
 +        }
 +
 +        self.span_suggestion(remove_span, msg, String::new(), applicability);
 +    }
 +}
 +
 +/// Suggestion results for handling closure
 +/// args dereferencing and borrowing
 +pub struct DerefClosure {
 +    /// confidence on the built suggestion
 +    pub applicability: Applicability,
 +    /// gradually built suggestion
 +    pub suggestion: String,
 +}
 +
 +/// Build suggestion gradually by handling closure arg specific usages,
 +/// such as explicit deref and borrowing cases.
 +/// Returns `None` if no such use cases have been triggered in closure body
 +///
 +/// note: this only works on single line immutable closures with exactly one input parameter.
 +pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
 +    if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = closure.kind {
 +        let closure_body = cx.tcx.hir().body(body_id);
 +        // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
 +        // a type annotation is present if param `kind` is different from `TyKind::Infer`
 +        let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
 +        {
 +            matches!(ty.kind, TyKind::Rptr(_, MutTy { .. }))
 +        } else {
 +            false
 +        };
 +
 +        let mut visitor = DerefDelegate {
 +            cx,
 +            closure_span: closure.span,
 +            closure_arg_is_type_annotated_double_ref,
 +            next_pos: closure.span.lo(),
 +            suggestion_start: String::new(),
 +            applicability: Applicability::MaybeIncorrect,
 +        };
 +
 +        let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
 +        cx.tcx.infer_ctxt().enter(|infcx| {
 +            ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
 +                .consume_body(closure_body);
 +        });
 +
 +        if !visitor.suggestion_start.is_empty() {
 +            return Some(DerefClosure {
 +                applicability: visitor.applicability,
 +                suggestion: visitor.finish(),
 +            });
 +        }
 +    }
 +    None
 +}
 +
 +/// Visitor struct used for tracking down
 +/// dereferencing and borrowing of closure's args
 +struct DerefDelegate<'a, 'tcx> {
 +    /// The late context of the lint
 +    cx: &'a LateContext<'tcx>,
 +    /// The span of the input closure to adapt
 +    closure_span: Span,
 +    /// Indicates if the arg of the closure is a type annotated double reference
 +    closure_arg_is_type_annotated_double_ref: bool,
 +    /// last position of the span to gradually build the suggestion
 +    next_pos: BytePos,
 +    /// starting part of the gradually built suggestion
 +    suggestion_start: String,
 +    /// confidence on the built suggestion
 +    applicability: Applicability,
 +}
 +
 +impl DerefDelegate<'_, 'tcx> {
 +    /// build final suggestion:
 +    /// - create the ending part of suggestion
 +    /// - concatenate starting and ending parts
 +    /// - potentially remove needless borrowing
 +    pub fn finish(&mut self) -> String {
 +        let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None);
 +        let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability);
 +        let sugg = format!("{}{}", self.suggestion_start, end_snip);
 +        if self.closure_arg_is_type_annotated_double_ref {
 +            sugg.replacen('&', "", 1)
 +        } else {
 +            sugg
 +        }
 +    }
 +
 +    /// indicates whether the function from `parent_expr` takes its args by double reference
 +    fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
 +        let (call_args, inputs) = match parent_expr.kind {
 +            ExprKind::MethodCall(_, _, call_args, _) => {
 +                if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) {
 +                    (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs())
 +                } else {
 +                    return false;
 +                }
 +            },
 +            ExprKind::Call(func, call_args) => {
 +                let typ = self.cx.typeck_results().expr_ty(func);
 +                (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs())
 +            },
 +            _ => return false,
 +        };
 +
 +        iter::zip(call_args, inputs)
 +            .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()))
 +    }
 +}
 +
 +impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
 +    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
 +        if let PlaceBase::Local(id) = cmt.place.base {
 +            let map = self.cx.tcx.hir();
 +            let span = map.span(cmt.hir_id);
 +            let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None);
 +            let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
 +
 +            // identifier referring to the variable currently triggered (i.e.: `fp`)
 +            let ident_str = map.name(id).to_string();
 +            // full identifier that includes projection (i.e.: `fp.field`)
 +            let ident_str_with_proj = snippet(self.cx, span, "..").to_string();
 +
 +            if cmt.place.projections.is_empty() {
 +                // handle item without any projection, that needs an explicit borrowing
 +                // i.e.: suggest `&x` instead of `x`
 +                self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str));
 +            } else {
 +                // cases where a parent `Call` or `MethodCall` is using the item
 +                // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
 +                //
 +                // Note about method calls:
 +                // - compiler automatically dereference references if the target type is a reference (works also for
 +                //   function call)
 +                // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and
 +                //   no projection should be suggested
 +                if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) {
 +                    match &parent_expr.kind {
 +                        // given expression is the self argument and will be handled completely by the compiler
 +                        // i.e.: `|x| x.is_something()`
 +                        ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
 +                            self.suggestion_start
 +                                .push_str(&format!("{}{}", start_snip, ident_str_with_proj));
 +                            self.next_pos = span.hi();
 +                            return;
 +                        },
 +                        // item is used in a call
 +                        // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
 +                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => {
 +                            let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
 +                            let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
 +
 +                            if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) {
 +                                // suggest ampersand if call function is taking args by double reference
 +                                let takes_arg_by_double_ref =
 +                                    self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id);
 +
 +                                // compiler will automatically dereference field or index projection, so no need
 +                                // to suggest ampersand, but full identifier that includes projection is required
 +                                let has_field_or_index_projection =
 +                                    cmt.place.projections.iter().any(|proj| {
 +                                        matches!(proj.kind, ProjectionKind::Field(..) | ProjectionKind::Index)
 +                                    });
 +
 +                                // no need to bind again if the function doesn't take arg by double ref
 +                                // and if the item is already a double ref
 +                                let ident_sugg = if !call_args.is_empty()
 +                                    && !takes_arg_by_double_ref
 +                                    && (self.closure_arg_is_type_annotated_double_ref || has_field_or_index_projection)
 +                                {
 +                                    let ident = if has_field_or_index_projection {
 +                                        ident_str_with_proj
 +                                    } else {
 +                                        ident_str
 +                                    };
 +                                    format!("{}{}", start_snip, ident)
 +                                } else {
 +                                    format!("{}&{}", start_snip, ident_str)
 +                                };
 +                                self.suggestion_start.push_str(&ident_sugg);
 +                                self.next_pos = span.hi();
 +                                return;
 +                            }
 +
 +                            self.applicability = Applicability::Unspecified;
 +                        },
 +                        _ => (),
 +                    }
 +                }
 +
 +                let mut replacement_str = ident_str;
 +                let mut projections_handled = false;
 +                cmt.place.projections.iter().enumerate().for_each(|(i, proj)| {
 +                    match proj.kind {
 +                        // Field projection like `|v| v.foo`
 +                        // no adjustment needed here, as field projections are handled by the compiler
 +                        ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() {
 +                            ty::Adt(..) | ty::Tuple(_) => {
 +                                replacement_str = ident_str_with_proj.clone();
 +                                projections_handled = true;
 +                            },
 +                            _ => (),
 +                        },
 +                        // Index projection like `|x| foo[x]`
 +                        // the index is dropped so we can't get it to build the suggestion,
 +                        // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`)
 +                        // instead of `span.lo()` (i.e.: `foo`)
 +                        ProjectionKind::Index => {
 +                            let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None);
 +                            start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
 +                            replacement_str.clear();
 +                            projections_handled = true;
 +                        },
 +                        // note: unable to trigger `Subslice` kind in tests
 +                        ProjectionKind::Subslice => (),
 +                        ProjectionKind::Deref => {
 +                            // Explicit derefs are typically handled later on, but
 +                            // some items do not need explicit deref, such as array accesses,
 +                            // so we mark them as already processed
 +                            // i.e.: don't suggest `*sub[1..4].len()` for `|sub| sub[1..4].len() == 3`
 +                            if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() {
 +                                if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) {
 +                                    projections_handled = true;
 +                                }
 +                            }
 +                        },
 +                    }
 +                });
 +
 +                // handle `ProjectionKind::Deref` by removing one explicit deref
 +                // if no special case was detected (i.e.: suggest `*x` instead of `**x`)
 +                if !projections_handled {
 +                    let last_deref = cmt
 +                        .place
 +                        .projections
 +                        .iter()
 +                        .rposition(|proj| proj.kind == ProjectionKind::Deref);
 +
 +                    if let Some(pos) = last_deref {
 +                        let mut projections = cmt.place.projections.clone();
 +                        projections.truncate(pos);
 +
 +                        for item in projections {
 +                            if item.kind == ProjectionKind::Deref {
 +                                replacement_str = format!("*{}", replacement_str);
 +                            }
 +                        }
 +                    }
 +                }
 +
 +                self.suggestion_start
 +                    .push_str(&format!("{}{}", start_snip, replacement_str));
 +            }
 +            self.next_pos = span.hi();
 +        }
 +    }
 +
 +    fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 +
 +    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::Sugg;
 +
 +    use rustc_ast::util::parser::AssocOp;
 +    use std::borrow::Cow;
 +
 +    const SUGGESTION: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("function_call()"));
 +
 +    #[test]
 +    fn make_return_transform_sugg_into_a_return_call() {
 +        assert_eq!("return function_call()", SUGGESTION.make_return().to_string());
 +    }
 +
 +    #[test]
 +    fn blockify_transforms_sugg_into_a_block() {
 +        assert_eq!("{ function_call() }", SUGGESTION.blockify().to_string());
 +    }
 +
 +    #[test]
 +    fn binop_maybe_par() {
-         let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1) + (1 + 1)".into());
++        let sugg = Sugg::BinOp(AssocOp::Add, "1".into(), "1".into());
 +        assert_eq!("(1 + 1)", sugg.maybe_par().to_string());
 +
++        let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into(), "(1 + 1)".into());
 +        assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string());
 +    }
++    #[test]
++    fn not_op() {
++        use AssocOp::{Add, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, NotEqual};
++
++        fn test_not(op: AssocOp, correct: &str) {
++            let sugg = Sugg::BinOp(op, "x".into(), "y".into());
++            assert_eq!((!sugg).to_string(), correct);
++        }
++
++        // Invert the comparison operator.
++        test_not(Equal, "x != y");
++        test_not(NotEqual, "x == y");
++        test_not(Less, "x >= y");
++        test_not(LessEqual, "x > y");
++        test_not(Greater, "x <= y");
++        test_not(GreaterEqual, "x < y");
++
++        // Other operators are inverted like !(..).
++        test_not(Add, "!(x + y)");
++        test_not(LAnd, "!(x && y)");
++        test_not(LOr, "!(x || y)");
++    }
 +}
index 3a5dfa6a8c7d8d4265be4ec5704b497c76bbe6b3,0000000000000000000000000000000000000000..471ae40f1ac7af43fb20fc1efb8f419a99c4c5f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-12-17"
 +[toolchain]
++channel = "nightly-2021-12-30"
 +components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index d7b49eb89a28bb437d14931edb435a3f6e5ec9a8,0000000000000000000000000000000000000000..111350a6280dc44a4415e30f74fe636f673c0f0e
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,15 @@@
- LL ~     // Safety: ...
 +error: unsafe block missing a safety comment
 +  --> $DIR/auxiliary/ice-7868-aux.rs:2:5
 +   |
 +LL |     unsafe { 0 };
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
 +help: consider adding a safety comment
 +   |
++LL ~     // SAFETY: ...
 +LL ~     unsafe { 0 };
 +   |
 +
 +error: aborting due to previous error
 +
index 083f5143e6e4d75c662975f2f847b63d83ea41bb,0000000000000000000000000000000000000000..d3662a0a213d2cc4b276a974efd8a111e318b509
mode 100644,000000..100644
--- /dev/null
@@@ -1,148 -1,0 +1,154 @@@
 +#![warn(clippy::enum_variant_names)]
 +#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
 +
 +enum FakeCallType {
 +    CALL,
 +    CREATE,
 +}
 +
 +enum FakeCallType2 {
 +    CALL,
 +    CREATELL,
 +}
 +
 +enum Foo {
 +    cFoo,
 +    cBar,
 +    cBaz,
 +}
 +
 +enum Fooo {
 +    cFoo, // no error, threshold is 3 variants by default
 +    cBar,
 +}
 +
 +enum Food {
 +    FoodGood,
 +    FoodMiddle,
 +    FoodBad,
 +}
 +
 +enum Stuff {
 +    StuffBad, // no error
 +}
 +
 +enum BadCallType {
 +    CallTypeCall,
 +    CallTypeCreate,
 +    CallTypeDestroy,
 +}
 +
 +enum TwoCallType {
 +    // no error
 +    CallTypeCall,
 +    CallTypeCreate,
 +}
 +
 +enum Consts {
 +    ConstantInt,
 +    ConstantCake,
 +    ConstantLie,
 +}
 +
 +enum Two {
 +    // no error here
 +    ConstantInt,
 +    ConstantInfer,
 +}
 +
 +enum Something {
 +    CCall,
 +    CCreate,
 +    CCryogenize,
 +}
 +
 +enum Seal {
 +    With,
 +    Without,
 +}
 +
 +enum Seall {
 +    With,
 +    WithOut,
 +    Withbroken,
 +}
 +
 +enum Sealll {
 +    With,
 +    WithOut,
 +}
 +
 +enum Seallll {
 +    WithOutCake,
 +    WithOutTea,
 +    WithOut,
 +}
 +
 +enum NonCaps {
 +    Prefix的,
 +    PrefixTea,
 +    PrefixCake,
 +}
 +
 +pub enum PubSeall {
 +    WithOutCake,
 +    WithOutTea,
 +    WithOut,
 +}
 +
 +#[allow(clippy::enum_variant_names)]
 +pub mod allowed {
 +    pub enum PubAllowed {
 +        SomeThis,
 +        SomeThat,
 +        SomeOtherWhat,
 +    }
 +}
 +
 +// should not lint
 +enum Pat {
 +    Foo,
 +    Bar,
 +    Path,
 +}
 +
 +// should not lint
 +enum N {
 +    Pos,
 +    Neg,
 +    Float,
 +}
 +
 +// should not lint
 +enum Peek {
 +    Peek1,
 +    Peek2,
 +    Peek3,
 +}
 +
 +// should not lint
 +pub enum NetworkLayer {
 +    Layer2,
 +    Layer3,
 +}
 +
 +// should lint suggesting `IData`, not only `Data` (see #4639)
 +enum IDataRequest {
 +    PutIData(String),
 +    GetIData(String),
 +    DeleteUnpubIData(String),
 +}
 +
 +enum HIDataRequest {
 +    PutHIData(String),
 +    GetHIData(String),
 +    DeleteUnpubHIData(String),
 +}
 +
++enum North {
++    Normal,
++    NoLeft,
++    NoRight,
++}
++
 +fn main() {}
index add8a91e26b85a2b9745a73053ff73d418a54cdd,0000000000000000000000000000000000000000..8a3265086e84fe146cef93d1e3aaad081b97f1c4
mode 100644,000000..100644
--- /dev/null
@@@ -1,112 -1,0 +1,124 @@@
- error: all variants have the same prefix: `WithOut`
-   --> $DIR/enum_variants.rs:81:1
 +error: variant name ends with the enum's name
 +  --> $DIR/enum_variants.rs:15:5
 +   |
 +LL |     cFoo,
 +   |     ^^^^
 +   |
 +   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 +
++error: all variants have the same prefix: `c`
++  --> $DIR/enum_variants.rs:14:1
++   |
++LL | / enum Foo {
++LL | |     cFoo,
++LL | |     cBar,
++LL | |     cBaz,
++LL | | }
++   | |_^
++   |
++   = help: remove the prefixes and use full paths to the variants instead of glob imports
++
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:26:5
 +   |
 +LL |     FoodGood,
 +   |     ^^^^^^^^
 +
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:27:5
 +   |
 +LL |     FoodMiddle,
 +   |     ^^^^^^^^^^
 +
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:28:5
 +   |
 +LL |     FoodBad,
 +   |     ^^^^^^^
 +
 +error: all variants have the same prefix: `Food`
 +  --> $DIR/enum_variants.rs:25:1
 +   |
 +LL | / enum Food {
 +LL | |     FoodGood,
 +LL | |     FoodMiddle,
 +LL | |     FoodBad,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same prefix: `CallType`
 +  --> $DIR/enum_variants.rs:35:1
 +   |
 +LL | / enum BadCallType {
 +LL | |     CallTypeCall,
 +LL | |     CallTypeCreate,
 +LL | |     CallTypeDestroy,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same prefix: `Constant`
 +  --> $DIR/enum_variants.rs:47:1
 +   |
 +LL | / enum Consts {
 +LL | |     ConstantInt,
 +LL | |     ConstantCake,
 +LL | |     ConstantLie,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
- LL | / enum Seallll {
- LL | |     WithOutCake,
- LL | |     WithOutTea,
- LL | |     WithOut,
++error: all variants have the same prefix: `C`
++  --> $DIR/enum_variants.rs:59:1
 +   |
- error: all variants have the same prefix: `Prefix`
-   --> $DIR/enum_variants.rs:87:1
++LL | / enum Something {
++LL | |     CCall,
++LL | |     CCreate,
++LL | |     CCryogenize,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
- LL | / enum NonCaps {
- LL | |     Prefix的,
- LL | |     PrefixTea,
- LL | |     PrefixCake,
++error: all variants have the same prefix: `WithOut`
++  --> $DIR/enum_variants.rs:81:1
 +   |
- error: aborting due to 11 previous errors
++LL | / enum Seallll {
++LL | |     WithOutCake,
++LL | |     WithOutTea,
++LL | |     WithOut,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same postfix: `IData`
 +  --> $DIR/enum_variants.rs:136:1
 +   |
 +LL | / enum IDataRequest {
 +LL | |     PutIData(String),
 +LL | |     GetIData(String),
 +LL | |     DeleteUnpubIData(String),
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the postfixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same postfix: `HIData`
 +  --> $DIR/enum_variants.rs:142:1
 +   |
 +LL | / enum HIDataRequest {
 +LL | |     PutHIData(String),
 +LL | |     GetHIData(String),
 +LL | |     DeleteUnpubHIData(String),
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the postfixes and use full paths to the variants instead of glob imports
 +
++error: aborting due to 12 previous errors
 +
index a35bb1c27f35c4150b687fbe3854a36d4e3c5ece,0000000000000000000000000000000000000000..ce91fe176c6fccec4fee57bc3339f7091e0e8827
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,25 @@@
 +// run-rustfix
 +#![feature(const_fn_floating_point_arithmetic)]
 +#![warn(clippy::suboptimal_flops)]
 +
 +/// Allow suboptimal_flops in constant context
 +pub const fn const_context() {
 +    let x = 3f32;
 +    let _ = x * 180f32 / std::f32::consts::PI;
 +}
 +
 +fn main() {
 +    let x = 3f32;
 +    let _ = x.to_degrees();
++    let _ = 90.0_f64.to_degrees();
++    let _ = 90.5_f64.to_degrees();
 +    let _ = x.to_radians();
++    let _ = 90.0_f64.to_radians();
++    let _ = 90.5_f64.to_radians();
++    // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32;
 +    // Cases where the lint shouldn't be applied
 +    let _ = x * 90f32 / std::f32::consts::PI;
 +    let _ = x * std::f32::consts::PI / 90f32;
 +    let _ = x * 180f32 / std::f32::consts::E;
 +    let _ = x * std::f32::consts::E / 180f32;
 +}
index 834db4be533c046dfc4ff96680b8d7552d06385a,0000000000000000000000000000000000000000..8f3234986148b70d302dd0f5ac04852feec89c16
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,25 @@@
 +// run-rustfix
 +#![feature(const_fn_floating_point_arithmetic)]
 +#![warn(clippy::suboptimal_flops)]
 +
 +/// Allow suboptimal_flops in constant context
 +pub const fn const_context() {
 +    let x = 3f32;
 +    let _ = x * 180f32 / std::f32::consts::PI;
 +}
 +
 +fn main() {
 +    let x = 3f32;
 +    let _ = x * 180f32 / std::f32::consts::PI;
++    let _ = 90. * 180f64 / std::f64::consts::PI;
++    let _ = 90.5 * 180f64 / std::f64::consts::PI;
 +    let _ = x * std::f32::consts::PI / 180f32;
++    let _ = 90. * std::f32::consts::PI / 180f32;
++    let _ = 90.5 * std::f32::consts::PI / 180f32;
++    // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32;
 +    // Cases where the lint shouldn't be applied
 +    let _ = x * 90f32 / std::f32::consts::PI;
 +    let _ = x * std::f32::consts::PI / 90f32;
 +    let _ = x * 180f32 / std::f32::consts::E;
 +    let _ = x * std::f32::consts::E / 180f32;
 +}
index acecddbca53bf6254503e6e1d5c07c0be3c47b33,0000000000000000000000000000000000000000..f12d3d23f3ab93fa38f53d5fc595857872e1d3a2
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,40 @@@
- error: conversion to radians can be done more accurately
 +error: conversion to degrees can be done more accurately
 +  --> $DIR/floating_point_rad.rs:13:13
 +   |
 +LL |     let _ = x * 180f32 / std::f32::consts::PI;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
 +   |
 +   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 +
- error: aborting due to 2 previous errors
++error: conversion to degrees can be done more accurately
 +  --> $DIR/floating_point_rad.rs:14:13
 +   |
++LL |     let _ = 90. * 180f64 / std::f64::consts::PI;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()`
++
++error: conversion to degrees can be done more accurately
++  --> $DIR/floating_point_rad.rs:15:13
++   |
++LL |     let _ = 90.5 * 180f64 / std::f64::consts::PI;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()`
++
++error: conversion to radians can be done more accurately
++  --> $DIR/floating_point_rad.rs:16:13
++   |
 +LL |     let _ = x * std::f32::consts::PI / 180f32;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
 +
++error: conversion to radians can be done more accurately
++  --> $DIR/floating_point_rad.rs:17:13
++   |
++LL |     let _ = 90. * std::f32::consts::PI / 180f32;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()`
++
++error: conversion to radians can be done more accurately
++  --> $DIR/floating_point_rad.rs:18:13
++   |
++LL |     let _ = 90.5 * std::f32::consts::PI / 180f32;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()`
++
++error: aborting due to 6 previous errors
 +
index ceaacaaf6bd706618ecac1133af2b63d9d261595,0000000000000000000000000000000000000000..2ed4b5db574d42aabae78102fc94d00e24c9b4ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,56 @@@
 +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 {
++        self.0.push_str(&format!("{}", other));
++        self
++    }
++}
 +#[allow(
 +    clippy::eq_op,
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
++    clippy::op_ref,
 +    clippy::double_parens
 +)]
 +#[warn(clippy::identity_op)]
 +#[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("".into());
++    let b = a << 0; // no error: non-integer
 +}
index d8d44a74f9ab0fb05c1b19f7566eb2be6ad3e7be,0000000000000000000000000000000000000000..ff34b38db015bbf49077a823bf35b03b5a45d050
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,82 @@@
-   --> $DIR/identity_op.rs:16:5
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:17:5
++  --> $DIR/identity_op.rs:26:5
 +   |
 +LL |     x + 0;
 +   |     ^^^^^
 +   |
 +   = note: `-D clippy::identity-op` implied by `-D warnings`
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:19:5
++  --> $DIR/identity_op.rs:27:5
 +   |
 +LL |     x + (1 - 1);
 +   |     ^^^^^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:22:5
++  --> $DIR/identity_op.rs:29:5
 +   |
 +LL |     0 + x;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:25:5
++  --> $DIR/identity_op.rs:32:5
 +   |
 +LL |     x | (0);
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:26:5
++  --> $DIR/identity_op.rs:35:5
 +   |
 +LL |     x * 1;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:32:5
++  --> $DIR/identity_op.rs:36:5
 +   |
 +LL |     1 * x;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
-   --> $DIR/identity_op.rs:35:5
++  --> $DIR/identity_op.rs:42:5
 +   |
 +LL |     -1 & x;
 +   |     ^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `u`
-   --> $DIR/identity_op.rs:38:5
++  --> $DIR/identity_op.rs:45:5
 +   |
 +LL |     u & 255;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `42`
-   --> $DIR/identity_op.rs:39:5
++  --> $DIR/identity_op.rs:48:5
 +   |
 +LL |     42 << 0;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `1`
-   --> $DIR/identity_op.rs:40:5
++  --> $DIR/identity_op.rs:49:5
 +   |
 +LL |     1 >> 0;
 +   |     ^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `42`
- error: aborting due to 11 previous errors
++  --> $DIR/identity_op.rs:50:5
 +   |
 +LL |     42 >> 0;
 +   |     ^^^^^^^
 +
++error: the operation is ineffective. Consider reducing it to `&x`
++  --> $DIR/identity_op.rs:51:5
++   |
++LL |     &x >> 0;
++   |     ^^^^^^^
++
++error: the operation is ineffective. Consider reducing it to `x`
++  --> $DIR/identity_op.rs:52:5
++   |
++LL |     x >> &0;
++   |     ^^^^^^^
++
++error: aborting due to 13 previous errors
 +
index 928b6acb95101648f9f4465e5a8495cbb79fa06c,0000000000000000000000000000000000000000..2db4c2bee7f2bc62db61af4877891a091dcba504
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,37 @@@
 +// run-rustfix
 +// aux-build:option_helpers.rs
 +
 +#![warn(clippy::iter_skip_next)]
 +#![allow(clippy::blacklisted_name)]
 +#![allow(clippy::iter_nth)]
++#![allow(unused_mut, dead_code)]
 +
 +extern crate option_helpers;
 +
 +use option_helpers::IteratorFalsePositives;
 +
 +/// Checks implementation of `ITER_SKIP_NEXT` lint
 +fn main() {
 +    let some_vec = vec![0, 1, 2, 3];
 +    let _ = some_vec.iter().nth(42);
 +    let _ = some_vec.iter().cycle().nth(42);
 +    let _ = (1..10).nth(10);
 +    let _ = &some_vec[..].iter().nth(3);
 +    let foo = IteratorFalsePositives { foo: 0 };
 +    let _ = foo.skip(42).next();
 +    let _ = foo.filter().skip(42).next();
++
++    // fix #8128
++    let test_string = "1|1 2";
++    let mut sp = test_string.split('|').map(|s| s.trim());
++    let _: Vec<&str> = sp.nth(1).unwrap().split(' ').collect();
++    if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) {
++        let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect();
++    };
++    fn check<T>(mut s: T)
++    where
++        T: Iterator<Item = String>,
++    {
++        let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect();
++    }
 +}
index 7075e2598ebee2903cdb6d70ab922190ccc2ec62,0000000000000000000000000000000000000000..692edb9aed9396386c1a04cc1e97d6725e337871
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,37 @@@
 +// run-rustfix
 +// aux-build:option_helpers.rs
 +
 +#![warn(clippy::iter_skip_next)]
 +#![allow(clippy::blacklisted_name)]
 +#![allow(clippy::iter_nth)]
++#![allow(unused_mut, dead_code)]
 +
 +extern crate option_helpers;
 +
 +use option_helpers::IteratorFalsePositives;
 +
 +/// Checks implementation of `ITER_SKIP_NEXT` lint
 +fn main() {
 +    let some_vec = vec![0, 1, 2, 3];
 +    let _ = some_vec.iter().skip(42).next();
 +    let _ = some_vec.iter().cycle().skip(42).next();
 +    let _ = (1..10).skip(10).next();
 +    let _ = &some_vec[..].iter().skip(3).next();
 +    let foo = IteratorFalsePositives { foo: 0 };
 +    let _ = foo.skip(42).next();
 +    let _ = foo.filter().skip(42).next();
++
++    // fix #8128
++    let test_string = "1|1 2";
++    let mut sp = test_string.split('|').map(|s| s.trim());
++    let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
++    if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) {
++        let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++    };
++    fn check<T>(mut s: T)
++    where
++        T: Iterator<Item = String>,
++    {
++        let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++    }
 +}
index 486de718bb563f9064338396bf07f16d1e7c7bfd,0000000000000000000000000000000000000000..ca6970b27f16c50fdff4e834cf08d55840ccf8c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,46 @@@
-   --> $DIR/iter_skip_next.rs:15:28
 +error: called `skip(..).next()` on an iterator
-   --> $DIR/iter_skip_next.rs:16:36
++  --> $DIR/iter_skip_next.rs:16:28
 +   |
 +LL |     let _ = some_vec.iter().skip(42).next();
 +   |                            ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
 +   |
 +   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
 +
 +error: called `skip(..).next()` on an iterator
-   --> $DIR/iter_skip_next.rs:17:20
++  --> $DIR/iter_skip_next.rs:17:36
 +   |
 +LL |     let _ = some_vec.iter().cycle().skip(42).next();
 +   |                                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
 +
 +error: called `skip(..).next()` on an iterator
-   --> $DIR/iter_skip_next.rs:18:33
++  --> $DIR/iter_skip_next.rs:18:20
 +   |
 +LL |     let _ = (1..10).skip(10).next();
 +   |                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)`
 +
 +error: called `skip(..).next()` on an iterator
- error: aborting due to 4 previous errors
++  --> $DIR/iter_skip_next.rs:19:33
 +   |
 +LL |     let _ = &some_vec[..].iter().skip(3).next();
 +   |                                 ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)`
 +
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next.rs:27:26
++   |
++LL |     let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
++   |                          ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next.rs:29:29
++   |
++LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++   |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next.rs:35:29
++   |
++LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++   |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++
++error: aborting due to 7 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3607330cfa0d370149a80375b2f0f6cc041c0d88
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++#![warn(clippy::iter_skip_next)]
++#![allow(dead_code)]
++
++/// Checks implementation of `ITER_SKIP_NEXT` lint
++fn main() {
++    // fix #8128
++    let test_string = "1|1 2";
++    let sp = test_string.split('|').map(|s| s.trim());
++    let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
++    if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) {
++        let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++    };
++    fn check<T>(s: T)
++    where
++        T: Iterator<Item = String>,
++    {
++        let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..74c327c748361df3feb10de6718e1b0fecfcbaf1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,39 @@@
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next_unfixable.rs:9:26
++   |
++LL |     let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
++   |                          ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++   |
++   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
++help: for this change `sp` has to be mutable
++  --> $DIR/iter_skip_next_unfixable.rs:8:9
++   |
++LL |     let sp = test_string.split('|').map(|s| s.trim());
++   |         ^^
++
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next_unfixable.rs:11:29
++   |
++LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++   |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++   |
++help: for this change `s` has to be mutable
++  --> $DIR/iter_skip_next_unfixable.rs:10:17
++   |
++LL |     if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) {
++   |                 ^
++
++error: called `skip(..).next()` on an iterator
++  --> $DIR/iter_skip_next_unfixable.rs:17:29
++   |
++LL |         let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect();
++   |                             ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
++   |
++help: for this change `s` has to be mutable
++  --> $DIR/iter_skip_next_unfixable.rs:13:17
++   |
++LL |     fn check<T>(s: T)
++   |                 ^
++
++error: aborting due to 3 previous errors
++
index 0243158dec50747ee4a944b7c8b08bb35c177f9b,0000000000000000000000000000000000000000..2e3ebadd7b5d2c580d2c89b09898d01b67f00adc
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,111 @@@
-    | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..((3 + src.len()) - 3)]);`
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:5:5
 +   |
 +LL | /     for i in 3..src.len() {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`
 +   |
 +   = note: `-D clippy::manual-memcpy` implied by `-D warnings`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:11:5
 +   |
 +LL | /     for i in 3..src.len() {
 +LL | |         dst[count] = src[i];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:17:5
 +   |
 +LL | /     for i in 0..src.len() {
 +LL | |         dst[count] = src[i];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:23:5
 +   |
 +LL | /     for i in 0..src.len() {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:29:5
 +   |
 +LL | /     for i in 3..(3 + src.len()) {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1;
 +LL | |     }
++   | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..(3 + src.len() - 3)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:35:5
 +   |
 +LL | /     for i in 5..src.len() {
 +LL | |         dst[i] = src[count - 2];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:41:5
 +   |
 +LL | /     for i in 0..dst.len() {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[2..(dst.len() + 2)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:47:5
 +   |
 +LL | /     for i in 3..10 {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:54:5
 +   |
 +LL | /     for i in 0..src.len() {
 +LL | |         dst[count] = src[i];
 +LL | |         dst2[count2] = src[i];
 +LL | |         count += 1;
 +LL | |         count2 += 1;
 +LL | |     }
 +   | |_____^
 +   |
 +help: try replacing the loop by
 +   |
 +LL ~     dst[3..(src.len() + 3)].clone_from_slice(&src[..]);
 +LL +     dst2[30..(src.len() + 30)].clone_from_slice(&src[..]);
 +   |
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:64:5
 +   |
 +LL | /     for i in 0..1 << 1 {
 +LL | |         dst[count] = src[i + 2];
 +LL | |         count += 1;
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);`
 +
 +error: it looks like you're manually copying between slices
 +  --> $DIR/with_loop_counters.rs:71:5
 +   |
 +LL | /     for i in 3..src.len() {
 +LL | |         dst[i] = src[count];
 +LL | |         count += 1
 +LL | |     }
 +   | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`
 +
 +error: aborting due to 11 previous errors
 +
index 85da1f4e10437cb6a3669e47b3dc3a35f5494913,0000000000000000000000000000000000000000..89dc13fd5b13d20077cfeecb305ea35fa20dcc2f
mode 100644,000000..100644
--- /dev/null
@@@ -1,117 -1,0 +1,126 @@@
 +// run-rustfix
 +
 +#![warn(clippy::needless_bool)]
 +#![allow(
 +    unused,
 +    dead_code,
 +    clippy::no_effect,
 +    clippy::if_same_then_else,
 +    clippy::equatable_if_let,
 +    clippy::needless_return,
 +    clippy::self_named_constructors
 +)]
 +
 +use std::cell::Cell;
 +
 +macro_rules! bool_comparison_trigger {
 +    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
 +
 +        #[derive(Clone)]
 +        pub struct Trigger {
 +            $($i: (Cell<bool>, bool, bool)),+
 +        }
 +
 +        #[allow(dead_code)]
 +        impl Trigger {
 +            pub fn trigger(&self, key: &str) -> bool {
 +                $(
 +                    if let stringify!($i) = key {
 +                        return self.$i.1 && self.$i.2 == $def;
 +                    }
 +                 )+
 +                false
 +            }
 +        }
 +    )
 +}
 +
 +fn main() {
 +    let x = true;
 +    let y = false;
 +    x;
 +    !x;
 +    !(x && y);
++    let a = 0;
++    let b = 1;
++
++    a != b;
++    a == b;
++    a >= b;
++    a > b;
++    a <= b;
++    a < b;
 +    if x {
 +        x
 +    } else {
 +        false
 +    }; // would also be questionable, but we don't catch this yet
 +    bool_ret3(x);
 +    bool_ret4(x);
 +    bool_ret5(x, x);
 +    bool_ret6(x, x);
 +    needless_bool(x);
 +    needless_bool2(x);
 +    needless_bool3(x);
 +    needless_bool_condition();
 +}
 +
 +fn bool_ret3(x: bool) -> bool {
 +    return x;
 +}
 +
 +fn bool_ret4(x: bool) -> bool {
 +    return !x;
 +}
 +
 +fn bool_ret5(x: bool, y: bool) -> bool {
 +    return x && y;
 +}
 +
 +fn bool_ret6(x: bool, y: bool) -> bool {
 +    return !(x && y);
 +}
 +
 +fn needless_bool(x: bool) {
 +    if x {};
 +}
 +
 +fn needless_bool2(x: bool) {
 +    if !x {};
 +}
 +
 +fn needless_bool3(x: bool) {
 +    bool_comparison_trigger! {
 +        test_one:   false, false;
 +        test_three: false, false;
 +        test_two:   true, true;
 +    }
 +
 +    if x {};
 +    if !x {};
 +}
 +
 +fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
 +    let b = false;
 +    let returns_bool = || false;
 +
 +    let x = if b {
 +        true
 +    } else { !returns_bool() };
 +}
 +
 +unsafe fn no(v: u8) -> u8 {
 +    v
 +}
 +
 +#[allow(clippy::unnecessary_operation)]
 +fn needless_bool_condition() -> bool {
 +    (unsafe { no(4) } & 1 != 0);
 +    let _brackets_unneeded = unsafe { no(4) } & 1 != 0;
 +    fn foo() -> bool {
 +        // parentheses are needed here
 +        (unsafe { no(4) } & 1 != 0)
 +    }
 +
 +    foo()
 +}
index add606302511b89dea3099e5fd13848ab0835f70,0000000000000000000000000000000000000000..c11d9472e8d066fa643c7472d4e2fa024c75eb7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,153 -1,0 +1,186 @@@
 +// run-rustfix
 +
 +#![warn(clippy::needless_bool)]
 +#![allow(
 +    unused,
 +    dead_code,
 +    clippy::no_effect,
 +    clippy::if_same_then_else,
 +    clippy::equatable_if_let,
 +    clippy::needless_return,
 +    clippy::self_named_constructors
 +)]
 +
 +use std::cell::Cell;
 +
 +macro_rules! bool_comparison_trigger {
 +    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
 +
 +        #[derive(Clone)]
 +        pub struct Trigger {
 +            $($i: (Cell<bool>, bool, bool)),+
 +        }
 +
 +        #[allow(dead_code)]
 +        impl Trigger {
 +            pub fn trigger(&self, key: &str) -> bool {
 +                $(
 +                    if let stringify!($i) = key {
 +                        return self.$i.1 && self.$i.2 == $def;
 +                    }
 +                 )+
 +                false
 +            }
 +        }
 +    )
 +}
 +
 +fn main() {
 +    let x = true;
 +    let y = false;
 +    if x {
 +        true
 +    } else {
 +        false
 +    };
 +    if x {
 +        false
 +    } else {
 +        true
 +    };
 +    if x && y {
 +        false
 +    } else {
 +        true
 +    };
++    let a = 0;
++    let b = 1;
++
++    if a == b {
++        false
++    } else {
++        true
++    };
++    if a != b {
++        false
++    } else {
++        true
++    };
++    if a < b {
++        false
++    } else {
++        true
++    };
++    if a <= b {
++        false
++    } else {
++        true
++    };
++    if a > b {
++        false
++    } else {
++        true
++    };
++    if a >= b {
++        false
++    } else {
++        true
++    };
 +    if x {
 +        x
 +    } else {
 +        false
 +    }; // would also be questionable, but we don't catch this yet
 +    bool_ret3(x);
 +    bool_ret4(x);
 +    bool_ret5(x, x);
 +    bool_ret6(x, x);
 +    needless_bool(x);
 +    needless_bool2(x);
 +    needless_bool3(x);
 +    needless_bool_condition();
 +}
 +
 +fn bool_ret3(x: bool) -> bool {
 +    if x {
 +        return true;
 +    } else {
 +        return false;
 +    };
 +}
 +
 +fn bool_ret4(x: bool) -> bool {
 +    if x {
 +        return false;
 +    } else {
 +        return true;
 +    };
 +}
 +
 +fn bool_ret5(x: bool, y: bool) -> bool {
 +    if x && y {
 +        return true;
 +    } else {
 +        return false;
 +    };
 +}
 +
 +fn bool_ret6(x: bool, y: bool) -> bool {
 +    if x && y {
 +        return false;
 +    } else {
 +        return true;
 +    };
 +}
 +
 +fn needless_bool(x: bool) {
 +    if x == true {};
 +}
 +
 +fn needless_bool2(x: bool) {
 +    if x == false {};
 +}
 +
 +fn needless_bool3(x: bool) {
 +    bool_comparison_trigger! {
 +        test_one:   false, false;
 +        test_three: false, false;
 +        test_two:   true, true;
 +    }
 +
 +    if x == true {};
 +    if x == false {};
 +}
 +
 +fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
 +    let b = false;
 +    let returns_bool = || false;
 +
 +    let x = if b {
 +        true
 +    } else if returns_bool() {
 +        false
 +    } else {
 +        true
 +    };
 +}
 +
 +unsafe fn no(v: u8) -> u8 {
 +    v
 +}
 +
 +#[allow(clippy::unnecessary_operation)]
 +fn needless_bool_condition() -> bool {
 +    if unsafe { no(4) } & 1 != 0 {
 +        true
 +    } else {
 +        false
 +    };
 +    let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
 +    fn foo() -> bool {
 +        // parentheses are needed here
 +        if unsafe { no(4) } & 1 != 0 { true } else { false }
 +    }
 +
 +    foo()
 +}
index 22c0a7bb491c6d495d47a9b418348ff85a79c185,0000000000000000000000000000000000000000..d2c48376f76622d0fe3528a76e92c45165261f31
mode 100644,000000..100644
--- /dev/null
@@@ -1,133 -1,0 +1,193 @@@
-   --> $DIR/fixable.rs:72:5
 +error: this if-then-else expression returns a bool literal
 +  --> $DIR/fixable.rs:41:5
 +   |
 +LL | /     if x {
 +LL | |         true
 +LL | |     } else {
 +LL | |         false
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `x`
 +   |
 +   = note: `-D clippy::needless-bool` implied by `-D warnings`
 +
 +error: this if-then-else expression returns a bool literal
 +  --> $DIR/fixable.rs:46:5
 +   |
 +LL | /     if x {
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `!x`
 +
 +error: this if-then-else expression returns a bool literal
 +  --> $DIR/fixable.rs:51:5
 +   |
 +LL | /     if x && y {
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `!(x && y)`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:80:5
++  --> $DIR/fixable.rs:59:5
++   |
++LL | /     if a == b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a != b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:64:5
++   |
++LL | /     if a != b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a == b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:69:5
++   |
++LL | /     if a < b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a >= b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:74:5
++   |
++LL | /     if a <= b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a > b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:79:5
++   |
++LL | /     if a > b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a <= b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:84:5
++   |
++LL | /     if a >= b {
++LL | |         false
++LL | |     } else {
++LL | |         true
++LL | |     };
++   | |_____^ help: you can reduce it to: `a < b`
++
++error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:105:5
 +   |
 +LL | /     if x {
 +LL | |         return true;
 +LL | |     } else {
 +LL | |         return false;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:88:5
++  --> $DIR/fixable.rs:113:5
 +   |
 +LL | /     if x {
 +LL | |         return false;
 +LL | |     } else {
 +LL | |         return true;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return !x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:96:5
++  --> $DIR/fixable.rs:121:5
 +   |
 +LL | /     if x && y {
 +LL | |         return true;
 +LL | |     } else {
 +LL | |         return false;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return x && y`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:104:8
++  --> $DIR/fixable.rs:129:5
 +   |
 +LL | /     if x && y {
 +LL | |         return false;
 +LL | |     } else {
 +LL | |         return true;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return !(x && y)`
 +
 +error: equality checks against true are unnecessary
-   --> $DIR/fixable.rs:108:8
++  --> $DIR/fixable.rs:137:8
 +   |
 +LL |     if x == true {};
 +   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 +   |
 +   = note: `-D clippy::bool-comparison` implied by `-D warnings`
 +
 +error: equality checks against false can be replaced by a negation
-   --> $DIR/fixable.rs:118:8
++  --> $DIR/fixable.rs:141:8
 +   |
 +LL |     if x == false {};
 +   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 +
 +error: equality checks against true are unnecessary
-   --> $DIR/fixable.rs:119:8
++  --> $DIR/fixable.rs:151:8
 +   |
 +LL |     if x == true {};
 +   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 +
 +error: equality checks against false can be replaced by a negation
-   --> $DIR/fixable.rs:128:12
++  --> $DIR/fixable.rs:152:8
 +   |
 +LL |     if x == false {};
 +   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:141:5
++  --> $DIR/fixable.rs:161:12
 +   |
 +LL |       } else if returns_bool() {
 +   |  ____________^
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:146:30
++  --> $DIR/fixable.rs:174:5
 +   |
 +LL | /     if unsafe { no(4) } & 1 != 0 {
 +LL | |         true
 +LL | |     } else {
 +LL | |         false
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:149:9
++  --> $DIR/fixable.rs:179:30
 +   |
 +LL |     let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
 +
 +error: this if-then-else expression returns a bool literal
- error: aborting due to 15 previous errors
++  --> $DIR/fixable.rs:182:9
 +   |
 +LL |         if unsafe { no(4) } & 1 != 0 { true } else { false }
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
 +
++error: aborting due to 21 previous errors
 +
index 83f467c84002621244adf95dc5e8f848b6efb755,0000000000000000000000000000000000000000..603d438d55889a8f72cb339beadf5031de43dfba
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,226 @@@
-         _ => {},
 +// run-rustfix
 +
 +#![feature(let_else)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::if_same_then_else,
 +    clippy::single_match,
 +    clippy::needless_bool,
 +    clippy::equatable_if_let
 +)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    true
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
-         _ => {},
++        _ => (),
++    }
++}
++
++fn test_nested_match(x: u32) {
++    match x {
++        0 => (),
++        1 => {
++            let _ = 42;
++            
++        },
++        _ => (),
 +    }
 +}
 +
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| {})
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            
 +        };
 +        let _ = || {};
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    true
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
++        _ => (),
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index 341caf18bd60c83f73b41ddf81bc99b9f36fd83f,0000000000000000000000000000000000000000..c6c8cb9ec152049e19929ab16092c4633f3b6112
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,226 @@@
 +// run-rustfix
 +
 +#![feature(let_else)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::if_same_then_else,
 +    clippy::single_match,
 +    clippy::needless_bool,
 +    clippy::equatable_if_let
 +)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    return;
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
++fn test_nested_match(x: u32) {
++    match x {
++        0 => (),
++        1 => {
++            let _ = 42;
++            return;
++        },
++        _ => return,
++    }
++}
++
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| return)
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            return;
 +        };
 +        let _ = || return;
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| return Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    return;
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index c0abc2c63dde1fb33c409476a3ab4ebdaac8823d,0000000000000000000000000000000000000000..5bc787c56a65bca559178a498e846a0ce6392942
mode 100644,000000..100644
--- /dev/null
@@@ -1,196 -1,0 +1,208 @@@
-    |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:24:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +   |
 +   = note: `-D clippy::needless-return` implied by `-D warnings`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:28:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:33:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:35:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:41:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:43:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:50:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:52:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:60:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:65:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:67:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:74:14
 +   |
 +LL |         _ => return,
-   --> $DIR/needless_return.rs:89:9
++   |              ^^^^^^ help: replace `return` with a unit value: `()`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:91:9
++  --> $DIR/needless_return.rs:83:13
++   |
++LL |             return;
++   |             ^^^^^^^ help: remove `return`
++
++error: unneeded `return` statement
++  --> $DIR/needless_return.rs:85:14
++   |
++LL |         _ => return,
++   |              ^^^^^^ help: replace `return` with a unit value: `()`
++
++error: unneeded `return` statement
++  --> $DIR/needless_return.rs:100:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:113:32
++  --> $DIR/needless_return.rs:102:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:118:13
++  --> $DIR/needless_return.rs:124:32
 +   |
 +LL |         bar.unwrap_or_else(|_| return)
 +   |                                ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:120:20
++  --> $DIR/needless_return.rs:129:13
 +   |
 +LL |             return;
 +   |             ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:126:32
++  --> $DIR/needless_return.rs:131:20
 +   |
 +LL |         let _ = || return;
 +   |                    ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:135:5
++  --> $DIR/needless_return.rs:137:32
 +   |
 +LL |         res.unwrap_or_else(|_| return Foo)
 +   |                                ^^^^^^^^^^ help: remove `return`: `Foo`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:139:5
++  --> $DIR/needless_return.rs:146:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:144:9
++  --> $DIR/needless_return.rs:150:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:146:9
++  --> $DIR/needless_return.rs:155:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:152:17
++  --> $DIR/needless_return.rs:157:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:154:13
++  --> $DIR/needless_return.rs:163:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:161:9
++  --> $DIR/needless_return.rs:165:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:163:16
++  --> $DIR/needless_return.rs:172:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:171:5
++  --> $DIR/needless_return.rs:174:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:176:9
++  --> $DIR/needless_return.rs:182:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:178:9
++  --> $DIR/needless_return.rs:187:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:185:14
++  --> $DIR/needless_return.rs:189:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-    |              ^^^^^^ help: replace `return` with an empty block: `{}`
++  --> $DIR/needless_return.rs:196:14
 +   |
 +LL |         _ => return,
-   --> $DIR/needless_return.rs:200:9
++   |              ^^^^^^ help: replace `return` with a unit value: `()`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:202:9
++  --> $DIR/needless_return.rs:211:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
- error: aborting due to 32 previous errors
++  --> $DIR/needless_return.rs:213:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
++error: aborting due to 34 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..35af9d6ae317f5c75424dabac4dee8786776f73f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++// run-rustfix
++#![warn(clippy::neg_multiply)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)]
++#![allow(unused)]
++
++use std::ops::Mul;
++
++struct X;
++
++impl Mul<isize> for X {
++    type Output = X;
++
++    fn mul(self, _r: isize) -> Self {
++        self
++    }
++}
++
++impl Mul<X> for isize {
++    type Output = X;
++
++    fn mul(self, _r: X) -> X {
++        X
++    }
++}
++
++fn main() {
++    let x = 0;
++
++    -x;
++
++    -x;
++
++    100 + -x;
++
++    -(100 + x);
++
++    -17;
++
++    0xcafe | -0xff00;
++
++    -1 * -1; // should be ok
++
++    X * -1; // should be ok
++    -1 * X; // should also be ok
++}
index d4a20ce9db1c843a3419ca44107a1aaf5f52dacd,0000000000000000000000000000000000000000..7dbdb0906ceeb3e7f17c3b480b94c141f25bad01
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,45 @@@
- #![allow(clippy::no_effect, clippy::unnecessary_operation)]
++// run-rustfix
 +#![warn(clippy::neg_multiply)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)]
++#![allow(unused)]
 +
 +use std::ops::Mul;
 +
 +struct X;
 +
 +impl Mul<isize> for X {
 +    type Output = X;
 +
 +    fn mul(self, _r: isize) -> Self {
 +        self
 +    }
 +}
 +
 +impl Mul<X> for isize {
 +    type Output = X;
 +
 +    fn mul(self, _r: X) -> X {
 +        X
 +    }
 +}
 +
 +fn main() {
 +    let x = 0;
 +
 +    x * -1;
 +
 +    -1 * x;
 +
++    100 + x * -1;
++
++    (100 + x) * -1;
++
++    -1 * 17;
++
++    0xcafe | 0xff00 * -1;
++
 +    -1 * -1; // should be ok
 +
 +    X * -1; // should be ok
 +    -1 * X; // should also be ok
 +}
index ad677f6d6fb9bf46c897fb122dc798883cb21ac4,0000000000000000000000000000000000000000..dbf8fb36938cbcbdd918c9d18656e32640e695e2
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,40 @@@
- error: negation by multiplying with `-1`
-   --> $DIR/neg_multiply.rs:27:5
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:29:5
 +   |
 +LL |     x * -1;
-    |     ^^^^^^
++   |     ^^^^^^ help: consider using: `-x`
 +   |
 +   = note: `-D clippy::neg-multiply` implied by `-D warnings`
 +
- error: negation by multiplying with `-1`
-   --> $DIR/neg_multiply.rs:29:5
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:31:5
 +   |
 +LL |     -1 * x;
-    |     ^^^^^^
++   |     ^^^^^^ help: consider using: `-x`
++
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:33:11
++   |
++LL |     100 + x * -1;
++   |           ^^^^^^ help: consider using: `-x`
++
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:35:5
++   |
++LL |     (100 + x) * -1;
++   |     ^^^^^^^^^^^^^^ help: consider using: `-(100 + x)`
++
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:37:5
++   |
++LL |     -1 * 17;
++   |     ^^^^^^^ help: consider using: `-17`
++
++error: this multiplication by -1 can be written more succinctly
++  --> $DIR/neg_multiply.rs:39:14
++   |
++LL |     0xcafe | 0xff00 * -1;
++   |              ^^^^^^^^^^^ help: consider using: `-0xff00`
 +
- error: aborting due to 2 previous errors
++error: aborting due to 6 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1da97e9687988aa856051a79a1a7b868b6b0d7b6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++//run-rustfix
++#![warn(clippy::init_numbered_fields)]
++
++#[derive(Default)]
++struct TupleStruct(u32, u32, u8);
++
++// This shouldn't lint because it's in a macro
++macro_rules! tuple_struct_init {
++    () => {
++        TupleStruct { 0: 0, 1: 1, 2: 2 }
++    };
++}
++
++fn main() {
++    let tuple_struct = TupleStruct::default();
++
++    // This should lint
++    let _ = TupleStruct(1u32, 42, 23u8);
++
++    // This should also lint and order the fields correctly
++    let _ = TupleStruct(1u32, 3u32, 2u8);
++
++    // Ok because of default initializer
++    let _ = TupleStruct { 0: 42, ..tuple_struct };
++
++    let _ = TupleStruct {
++        1: 23,
++        ..TupleStruct::default()
++    };
++
++    // Ok because it's in macro
++    let _ = tuple_struct_init!();
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..08ec405a5606e2ae8772754dbcf35697ad5b4cdb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++//run-rustfix
++#![warn(clippy::init_numbered_fields)]
++
++#[derive(Default)]
++struct TupleStruct(u32, u32, u8);
++
++// This shouldn't lint because it's in a macro
++macro_rules! tuple_struct_init {
++    () => {
++        TupleStruct { 0: 0, 1: 1, 2: 2 }
++    };
++}
++
++fn main() {
++    let tuple_struct = TupleStruct::default();
++
++    // This should lint
++    let _ = TupleStruct {
++        0: 1u32,
++        1: 42,
++        2: 23u8,
++    };
++
++    // This should also lint and order the fields correctly
++    let _ = TupleStruct {
++        0: 1u32,
++        2: 2u8,
++        1: 3u32,
++    };
++
++    // Ok because of default initializer
++    let _ = TupleStruct { 0: 42, ..tuple_struct };
++
++    let _ = TupleStruct {
++        1: 23,
++        ..TupleStruct::default()
++    };
++
++    // Ok because it's in macro
++    let _ = tuple_struct_init!();
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..01691c8b141e8a3ad7ac998739f5eb08b4f0a7c4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++error: used a field initializer for a tuple struct
++  --> $DIR/numbered_fields.rs:18:13
++   |
++LL |       let _ = TupleStruct {
++   |  _____________^
++LL | |         0: 1u32,
++LL | |         1: 42,
++LL | |         2: 23u8,
++LL | |     };
++   | |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)`
++   |
++   = note: `-D clippy::init-numbered-fields` implied by `-D warnings`
++
++error: used a field initializer for a tuple struct
++  --> $DIR/numbered_fields.rs:25:13
++   |
++LL |       let _ = TupleStruct {
++   |  _____________^
++LL | |         0: 1u32,
++LL | |         2: 2u8,
++LL | |         1: 3u32,
++LL | |     };
++   | |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)`
++
++error: aborting due to 2 previous errors
++
index bdf3f3d799582085b2b39a341445074f18e603b2,0000000000000000000000000000000000000000..7dd5742dae9f213d5038af6d0422b6b201342db6
mode 100644,000000..100644
--- /dev/null
@@@ -1,42 -1,0 +1,57 @@@
-     // There should be no warning here!
 +#![crate_type = "lib"]
 +
 +#[derive(Clone)]
 +pub struct Bar;
 +
 +pub trait Whatever {
 +    fn what(&self) -> Self;
-     // There should be no warning here!
++    // There should be no warning here! (returns a reference)
 +    fn what2(&self) -> &Self;
 +}
 +
 +impl Bar {
-     // There should be no warning here!
++    // There should be no warning here! (note taking a self argument)
 +    pub fn not_new() -> Self {
 +        Self
 +    }
 +    pub fn foo(&self) -> Self {
 +        Self
 +    }
 +    pub fn bar(self) -> Self {
 +        self
 +    }
-     // There should be no warning here!
++    // There should be no warning here! (private method)
 +    fn foo2(&self) -> Self {
 +        Self
 +    }
-     // There should be no warning here!
++    // There should be no warning here! (returns a reference)
 +    pub fn foo3(&self) -> &Self {
 +        self
 +    }
++    // There should be no warning here! (already a `must_use` attribute)
++    #[must_use]
++    pub fn foo4(&self) -> Self {
++        Self
++    }
 +}
 +
 +impl Whatever for Bar {
-     // There should be no warning here!
++    // There should be no warning here! (comes from the trait)
 +    fn what(&self) -> Self {
 +        self.foo2()
 +    }
++    // There should be no warning here! (comes from the trait)
 +    fn what2(&self) -> &Self {
 +        self
 +    }
 +}
++
++#[must_use]
++pub struct Foo;
++
++impl Foo {
++    // There should be no warning here! (`Foo` already implements `#[must_use]`)
++    fn foo(&self) -> Self {
++        Self
++    }
++}
index 06f6949b66f5abbd50a2b59efea216d6d9e1413f,0000000000000000000000000000000000000000..0321f8c4cdf84ba14f107536ba7019033d09d851
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,90 @@@
 +#![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
 +
 +fn shadow_same() {
 +    let x = 1;
 +    let x = x;
 +    let mut x = &x;
 +    let x = &mut x;
 +    let x = *x;
 +}
 +
 +fn shadow_reuse() -> Option<()> {
 +    let x = ([[0]], ());
 +    let x = x.0;
 +    let x = x[0];
 +    let [x] = x;
 +    let x = Some(x);
 +    let x = foo(x);
 +    let x = || x;
 +    let x = Some(1).map(|_| x)?;
 +    let y = 1;
 +    let y = match y {
 +        1 => 2,
 +        _ => 3,
 +    };
 +    None
 +}
 +
 +fn shadow_unrelated() {
 +    let x = 1;
 +    let x = 2;
 +}
 +
 +fn syntax() {
 +    fn f(x: u32) {
 +        let x = 1;
 +    }
 +    let x = 1;
 +    match Some(1) {
 +        Some(1) => {},
 +        Some(x) => {
 +            let x = 1;
 +        },
 +        _ => {},
 +    }
 +    if let Some(x) = Some(1) {}
 +    while let Some(x) = Some(1) {}
 +    let _ = |[x]: [u32; 1]| {
 +        let x = 1;
 +    };
++    let y = Some(1);
++    if let Some(y) = y {}
 +}
 +
 +fn negative() {
 +    match Some(1) {
 +        Some(x) if x == 1 => {},
 +        Some(x) => {},
 +        None => {},
 +    }
 +    match [None, Some(1)] {
 +        [Some(x), None] | [None, Some(x)] => {},
 +        _ => {},
 +    }
 +    if let Some(x) = Some(1) {
 +        let y = 1;
 +    } else {
 +        let x = 1;
 +        let y = 1;
 +    }
 +    let x = 1;
 +    #[allow(clippy::shadow_unrelated)]
 +    let x = 1;
 +}
 +
 +fn foo<T>(_: T) {}
 +
 +fn question_mark() -> Option<()> {
 +    let val = 1;
 +    // `?` expands with a `val` binding
 +    None?;
 +    None
 +}
 +
 +pub async fn foo1(_a: i32) {}
 +
 +pub async fn foo2(_a: i32, _b: i64) {
 +    let _b = _a;
 +}
 +
 +fn main() {}
index dcc7d4e6b2ff90adf0c8e463d4cbb0d285deafc0,0000000000000000000000000000000000000000..f8b9221d555871d7f6fbd4378857a619da51f41f
mode 100644,000000..100644
--- /dev/null
@@@ -1,257 -1,0 +1,269 @@@
-   --> $DIR/shadow.rs:85:9
 +error: `x` is shadowed by itself in `x`
 +  --> $DIR/shadow.rs:5:9
 +   |
 +LL |     let x = x;
 +   |         ^
 +   |
 +   = note: `-D clippy::shadow-same` implied by `-D warnings`
 +note: previous binding is here
 +  --> $DIR/shadow.rs:4:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `mut x` is shadowed by itself in `&x`
 +  --> $DIR/shadow.rs:6:13
 +   |
 +LL |     let mut x = &x;
 +   |             ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:5:9
 +   |
 +LL |     let x = x;
 +   |         ^
 +
 +error: `x` is shadowed by itself in `&mut x`
 +  --> $DIR/shadow.rs:7:9
 +   |
 +LL |     let x = &mut x;
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:6:9
 +   |
 +LL |     let mut x = &x;
 +   |         ^^^^^
 +
 +error: `x` is shadowed by itself in `*x`
 +  --> $DIR/shadow.rs:8:9
 +   |
 +LL |     let x = *x;
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:7:9
 +   |
 +LL |     let x = &mut x;
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:13:9
 +   |
 +LL |     let x = x.0;
 +   |         ^
 +   |
 +   = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 +note: previous binding is here
 +  --> $DIR/shadow.rs:12:9
 +   |
 +LL |     let x = ([[0]], ());
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:14:9
 +   |
 +LL |     let x = x[0];
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:13:9
 +   |
 +LL |     let x = x.0;
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:15:10
 +   |
 +LL |     let [x] = x;
 +   |          ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:14:9
 +   |
 +LL |     let x = x[0];
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:16:9
 +   |
 +LL |     let x = Some(x);
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:15:10
 +   |
 +LL |     let [x] = x;
 +   |          ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:17:9
 +   |
 +LL |     let x = foo(x);
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:16:9
 +   |
 +LL |     let x = Some(x);
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:18:9
 +   |
 +LL |     let x = || x;
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:17:9
 +   |
 +LL |     let x = foo(x);
 +   |         ^
 +
 +error: `x` is shadowed
 +  --> $DIR/shadow.rs:19:9
 +   |
 +LL |     let x = Some(1).map(|_| x)?;
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:18:9
 +   |
 +LL |     let x = || x;
 +   |         ^
 +
 +error: `y` is shadowed
 +  --> $DIR/shadow.rs:21:9
 +   |
 +LL |     let y = match y {
 +   |         ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:20:9
 +   |
 +LL |     let y = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:30:9
 +   |
 +LL |     let x = 2;
 +   |         ^
 +   |
 +   = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 +note: previous binding is here
 +  --> $DIR/shadow.rs:29:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:35:13
 +   |
 +LL |         let x = 1;
 +   |             ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:34:10
 +   |
 +LL |     fn f(x: u32) {
 +   |          ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:40:14
 +   |
 +LL |         Some(x) => {
 +   |              ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:37:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:41:17
 +   |
 +LL |             let x = 1;
 +   |                 ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:40:14
 +   |
 +LL |         Some(x) => {
 +   |              ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:45:17
 +   |
 +LL |     if let Some(x) = Some(1) {}
 +   |                 ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:37:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:46:20
 +   |
 +LL |     while let Some(x) = Some(1) {}
 +   |                    ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:37:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:47:15
 +   |
 +LL |     let _ = |[x]: [u32; 1]| {
 +   |               ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:37:9
 +   |
 +LL |     let x = 1;
 +   |         ^
 +
 +error: `x` shadows a previous, unrelated binding
 +  --> $DIR/shadow.rs:48:13
 +   |
 +LL |         let x = 1;
 +   |             ^
 +   |
 +note: previous binding is here
 +  --> $DIR/shadow.rs:47:15
 +   |
 +LL |     let _ = |[x]: [u32; 1]| {
 +   |               ^
 +
++error: `y` is shadowed
++  --> $DIR/shadow.rs:51:17
++   |
++LL |     if let Some(y) = y {}
++   |                 ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:50:9
++   |
++LL |     let y = Some(1);
++   |         ^
++
 +error: `_b` shadows a previous, unrelated binding
-   --> $DIR/shadow.rs:84:28
++  --> $DIR/shadow.rs:87:9
 +   |
 +LL |     let _b = _a;
 +   |         ^^
 +   |
 +note: previous binding is here
- error: aborting due to 21 previous errors
++  --> $DIR/shadow.rs:86:28
 +   |
 +LL | pub async fn foo2(_a: i32, _b: i64) {
 +   |                            ^^
 +
++error: aborting due to 22 previous errors
 +
index af0a397bd1aff0339695868b93d5d9aa38dd01b8,0000000000000000000000000000000000000000..dd22ecab0b551593f959cb7ce425318866ea09ee
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,18 @@@
-     if !(1 == 2) { g(); }
 +// run-rustfix
 +
 +#![warn(clippy::short_circuit_statement)]
 +#![allow(clippy::nonminimal_bool)]
 +
 +fn main() {
 +    if f() { g(); }
 +    if !f() { g(); }
++    if 1 != 2 { g(); }
 +}
 +
 +fn f() -> bool {
 +    true
 +}
 +
 +fn g() -> bool {
 +    false
 +}
index 0a3f60c3d132db57852c9cc2190db75f2eb357de,0000000000000000000000000000000000000000..aa84ac3a7925f3e6d0f741dd1d244b3c5b46209e
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,22 @@@
-    |     ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }`
 +error: boolean short circuit operator in statement may be clearer using an explicit test
 +  --> $DIR/short_circuit_statement.rs:7:5
 +   |
 +LL |     f() && g();
 +   |     ^^^^^^^^^^^ help: replace it with: `if f() { g(); }`
 +   |
 +   = note: `-D clippy::short-circuit-statement` implied by `-D warnings`
 +
 +error: boolean short circuit operator in statement may be clearer using an explicit test
 +  --> $DIR/short_circuit_statement.rs:8:5
 +   |
 +LL |     f() || g();
 +   |     ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }`
 +
 +error: boolean short circuit operator in statement may be clearer using an explicit test
 +  --> $DIR/short_circuit_statement.rs:9:5
 +   |
 +LL |     1 == 2 || g();
++   |     ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }`
 +
 +error: aborting due to 3 previous errors
 +
index 7e510d8947522e3bf871893e6cca28a9e60845a0,0000000000000000000000000000000000000000..380303d8152aae2bfc56d37e7a09ddf660f46302
mode 100644,000000..100644
--- /dev/null
@@@ -1,291 -1,0 +1,291 @@@
-             // Safety:
 +#![warn(clippy::undocumented_unsafe_blocks)]
 +
 +// Valid comments
 +
 +fn nested_local() {
 +    let _ = {
 +        let _ = {
-             // Safety:
++            // SAFETY:
 +            let _ = unsafe {};
 +        };
 +    };
 +}
 +
 +fn deep_nest() {
 +    let _ = {
 +        let _ = {
-                                 // Safety:
++            // SAFETY:
 +            let _ = unsafe {};
 +
 +            // Safety:
 +            unsafe {};
 +
 +            let _ = {
 +                let _ = {
 +                    let _ = {
 +                        let _ = {
 +                            let _ = {
 +                                // Safety:
 +                                let _ = unsafe {};
 +
-     // Safety:
++                                // SAFETY:
 +                                unsafe {};
 +                            };
 +                        };
 +                    };
 +
 +                    // Safety:
 +                    unsafe {};
 +                };
 +            };
 +        };
 +
 +        // Safety:
 +        unsafe {};
 +    };
 +
-     // Safety:
++    // SAFETY:
 +    unsafe {};
 +}
 +
 +fn local_tuple_expression() {
 +    // Safety:
 +    let _ = (42, unsafe {});
 +}
 +
 +fn line_comment() {
 +    // Safety:
 +    unsafe {}
 +}
 +
 +fn line_comment_newlines() {
-     /* Safety: */
++    // SAFETY:
 +
 +    unsafe {}
 +}
 +
 +fn line_comment_empty() {
 +    // Safety:
 +    //
 +    //
 +    //
 +    unsafe {}
 +}
 +
 +fn line_comment_with_extras() {
 +    // This is a description
 +    // Safety:
 +    unsafe {}
 +}
 +
 +fn block_comment() {
 +    /* Safety: */
 +    unsafe {}
 +}
 +
 +fn block_comment_newlines() {
-      * Safety:
++    /* SAFETY: */
 +
 +    unsafe {}
 +}
 +
 +#[rustfmt::skip]
 +fn inline_block_comment() {
 +    /* Safety: */unsafe {}
 +}
 +
 +fn block_comment_with_extras() {
 +    /* This is a description
-     // This is a test. Safety:
++     * SAFETY:
 +     */
 +    unsafe {}
 +}
 +
 +fn block_comment_terminator_same_line() {
 +    /* This is a description
 +     * Safety: */
 +    unsafe {}
 +}
 +
 +fn buried_safety() {
 +    // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
 +    // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
 +    // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
 +    // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
 +    // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
 +    // laborum. Safety:
 +    // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
 +    // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
 +    // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
 +    // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
 +    unsafe {}
 +}
 +
 +fn safety_with_prepended_text() {
-     /* Safety: */
++    // This is a test. safety:
 +    unsafe {}
 +}
 +
 +fn local_line_comment() {
 +    // Safety:
 +    let _ = unsafe {};
 +}
 +
 +fn local_block_comment() {
-     // Safety:
++    /* SAFETY: */
 +    let _ = unsafe {};
 +}
 +
 +fn comment_array() {
 +    // Safety:
 +    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +}
 +
 +fn comment_tuple() {
-     // Safety:
++    // sAFETY:
 +    let _ = (42, unsafe {}, "test", unsafe {});
 +}
 +
 +fn comment_unary() {
-     // Safety:
++    // SAFETY:
 +    let _ = *unsafe { &42 };
 +}
 +
 +#[allow(clippy::match_single_binding)]
 +fn comment_match() {
-         // Safety:
++    // SAFETY:
 +    let _ = match unsafe {} {
 +        _ => {},
 +    };
 +}
 +
 +fn comment_addr_of() {
 +    // Safety:
 +    let _ = &unsafe {};
 +}
 +
 +fn comment_repeat() {
 +    // Safety:
 +    let _ = [unsafe {}; 5];
 +}
 +
 +fn comment_macro_call() {
 +    macro_rules! t {
 +        ($b:expr) => {
 +            $b
 +        };
 +    }
 +
 +    t!(
-     // ॐ᧻໒ Safety: ௵∰
++        // SAFETY:
 +        unsafe {}
 +    );
 +}
 +
 +fn comment_macro_def() {
 +    macro_rules! t {
 +        () => {
 +            // Safety:
 +            unsafe {}
 +        };
 +    }
 +
 +    t!();
 +}
 +
 +fn non_ascii_comment() {
-         // Safety:
++    // ॐ᧻໒ SaFeTy: ௵∰
 +    unsafe {};
 +}
 +
 +fn local_commented_block() {
 +    let _ =
-     // Safety:
++        // safety:
 +        unsafe {};
 +}
 +
 +fn local_nest() {
-     unsafe {} // Safety:
++    // safety:
 +    let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
 +}
 +
 +// Invalid comments
 +
 +fn no_comment() {
 +    unsafe {}
 +}
 +
 +fn no_comment_array() {
 +    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +}
 +
 +fn no_comment_tuple() {
 +    let _ = (42, unsafe {}, "test", unsafe {});
 +}
 +
 +fn no_comment_unary() {
 +    let _ = *unsafe { &42 };
 +}
 +
 +#[allow(clippy::match_single_binding)]
 +fn no_comment_match() {
 +    let _ = match unsafe {} {
 +        _ => {},
 +    };
 +}
 +
 +fn no_comment_addr_of() {
 +    let _ = &unsafe {};
 +}
 +
 +fn no_comment_repeat() {
 +    let _ = [unsafe {}; 5];
 +}
 +
 +fn local_no_comment() {
 +    let _ = unsafe {};
 +}
 +
 +fn no_comment_macro_call() {
 +    macro_rules! t {
 +        ($b:expr) => {
 +            $b
 +        };
 +    }
 +
 +    t!(unsafe {});
 +}
 +
 +fn no_comment_macro_def() {
 +    macro_rules! t {
 +        () => {
 +            unsafe {}
 +        };
 +    }
 +
 +    t!();
 +}
 +
 +fn trailing_comment() {
-         // Safety:
++    unsafe {} // SAFETY:
 +}
 +
 +fn internal_comment() {
 +    unsafe {
-     // Safety
++        // SAFETY:
 +    }
 +}
 +
 +fn interference() {
++    // SAFETY
 +
 +    let _ = 42;
 +
 +    unsafe {};
 +}
 +
 +pub fn print_binary_tree() {
 +    println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
 +}
 +
 +fn main() {}
index ebe589001a1fe563bf320a94cb08ac12b6978719,0000000000000000000000000000000000000000..f69d0da54e0d6cf4fdb21a80aa73244b5d38e7c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,171 @@@
- LL ~     // Safety: ...
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:215:5
 +   |
 +LL |     unsafe {}
 +   |     ^^^^^^^^^
 +   |
 +   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     unsafe {}
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:219:5
 +   |
 +LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:223:5
 +   |
 +LL |     let _ = (42, unsafe {}, "test", unsafe {});
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = (42, unsafe {}, "test", unsafe {});
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:227:5
 +   |
 +LL |     let _ = *unsafe { &42 };
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = *unsafe { &42 };
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:232:5
 +   |
 +LL |     let _ = match unsafe {} {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = match unsafe {} {
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:238:5
 +   |
 +LL |     let _ = &unsafe {};
 +   |     ^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = &unsafe {};
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:242:5
 +   |
 +LL |     let _ = [unsafe {}; 5];
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = [unsafe {}; 5];
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:246:5
 +   |
 +LL |     let _ = unsafe {};
 +   |     ^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     t!(// Safety: ...
++LL ~     // SAFETY: ...
 +LL +     let _ = unsafe {};
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:256:8
 +   |
 +LL |     t!(unsafe {});
 +   |        ^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL |     unsafe {} // Safety:
++LL ~     t!(// SAFETY: ...
 +LL ~     unsafe {});
 +   |
 +
 +error: unsafe block in macro expansion missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:262:13
 +   |
 +LL |             unsafe {}
 +   |             ^^^^^^^^^
 +...
 +LL |     t!();
 +   |     ---- in this macro invocation
 +   |
 +   = help: consider adding a safety comment in the macro definition
 +   = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:270:5
 +   |
- LL ~     // Safety: ...
- LL ~     unsafe {} // Safety:
++LL |     unsafe {} // SAFETY:
 +   |     ^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
++LL ~     unsafe {} // SAFETY:
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:274:5
 +   |
 +LL |     unsafe {
 +   |     ^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     // Safety: ...
++LL ~     // SAFETY: ...
 +LL +     unsafe {
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:284:5
 +   |
 +LL |     unsafe {};
 +   |     ^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
- LL ~     println!("{}", // Safety: ...
++LL ~     // SAFETY: ...
 +LL ~     unsafe {};
 +   |
 +
 +error: unsafe block missing a safety comment
 +  --> $DIR/undocumented_unsafe_blocks.rs:288:20
 +   |
 +LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a safety comment
 +   |
++LL ~     println!("{}", // SAFETY: ...
 +LL ~     unsafe { String::from_utf8_unchecked(vec![]) });
 +   |
 +
 +error: aborting due to 14 previous errors
 +
index 7ac3f426c9775c5062aa3260f00a2e0247e6757e,0000000000000000000000000000000000000000..c2b9bd2c881fe916b8e2f789dcf3bce7de18b1ee
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,74 @@@
-     with_new.unwrap_or_else(Vec::new);
 +// run-rustfix
 +
 +#![warn(clippy::unwrap_or_else_default)]
 +#![allow(dead_code)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
 +fn unwrap_or_else_default() {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo
 +        }
 +
 +        // fake default, we should not trigger on this
 +        fn default() -> Foo {
 +            Foo
 +        }
 +    }
 +
 +    struct HasDefaultAndDuplicate;
 +
 +    impl HasDefaultAndDuplicate {
 +        fn default() -> Self {
 +            HasDefaultAndDuplicate
 +        }
 +    }
 +
 +    impl Default for HasDefaultAndDuplicate {
 +        fn default() -> Self {
 +            HasDefaultAndDuplicate
 +        }
 +    }
 +
 +    enum Enum {
 +        A(),
 +    }
 +
 +    fn make<T, V>(_: V) -> T {
 +        unimplemented!();
 +    }
 +
 +    let with_enum = Some(Enum::A());
 +    with_enum.unwrap_or_else(Enum::A);
 +
 +    let with_new = Some(vec![1]);
++    with_new.unwrap_or_default();
 +
 +    let with_err: Result<_, ()> = Ok(vec![1]);
 +    with_err.unwrap_or_else(make);
 +
 +    // should not be changed
 +    let with_fake_default = None::<Foo>;
 +    with_fake_default.unwrap_or_else(Foo::default);
 +
 +    // should not be changed
 +    let with_fake_default2 = None::<HasDefaultAndDuplicate>;
 +    with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
 +
 +    let with_real_default = None::<HasDefaultAndDuplicate>;
 +    with_real_default.unwrap_or_default();
 +
 +    let with_default_trait = Some(1);
 +    with_default_trait.unwrap_or_default();
 +
 +    let with_default_type = Some(1);
 +    with_default_type.unwrap_or_default();
++
++    let with_default_type: Option<Vec<u64>> = None;
++    with_default_type.unwrap_or_default();
 +}
 +
 +fn main() {}
index 82b727a039ed44fd18d5738c24a5cc2e3ec30c73,0000000000000000000000000000000000000000..d55664990aeb96f6dbbcf30869fc602538604329
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,74 @@@
 +// run-rustfix
 +
 +#![warn(clippy::unwrap_or_else_default)]
 +#![allow(dead_code)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
 +fn unwrap_or_else_default() {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo
 +        }
 +
 +        // fake default, we should not trigger on this
 +        fn default() -> Foo {
 +            Foo
 +        }
 +    }
 +
 +    struct HasDefaultAndDuplicate;
 +
 +    impl HasDefaultAndDuplicate {
 +        fn default() -> Self {
 +            HasDefaultAndDuplicate
 +        }
 +    }
 +
 +    impl Default for HasDefaultAndDuplicate {
 +        fn default() -> Self {
 +            HasDefaultAndDuplicate
 +        }
 +    }
 +
 +    enum Enum {
 +        A(),
 +    }
 +
 +    fn make<T, V>(_: V) -> T {
 +        unimplemented!();
 +    }
 +
 +    let with_enum = Some(Enum::A());
 +    with_enum.unwrap_or_else(Enum::A);
 +
 +    let with_new = Some(vec![1]);
 +    with_new.unwrap_or_else(Vec::new);
 +
 +    let with_err: Result<_, ()> = Ok(vec![1]);
 +    with_err.unwrap_or_else(make);
 +
 +    // should not be changed
 +    let with_fake_default = None::<Foo>;
 +    with_fake_default.unwrap_or_else(Foo::default);
 +
 +    // should not be changed
 +    let with_fake_default2 = None::<HasDefaultAndDuplicate>;
 +    with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
 +
 +    let with_real_default = None::<HasDefaultAndDuplicate>;
 +    with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
 +
 +    let with_default_trait = Some(1);
 +    with_default_trait.unwrap_or_else(Default::default);
 +
 +    let with_default_type = Some(1);
 +    with_default_type.unwrap_or_else(u64::default);
++
++    let with_default_type: Option<Vec<u64>> = None;
++    with_default_type.unwrap_or_else(Vec::new);
 +}
 +
 +fn main() {}
index feb215b09f662ef4e05dc536a7f6b1b25020fb07,0000000000000000000000000000000000000000..53e31d85edfca277bab0061c7815eb5c18199c6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,34 @@@
-    |
-    = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
++error: use of `.unwrap_or_else(..)` to construct default value
++  --> $DIR/unwrap_or_else_default.rs:48:5
++   |
++LL |     with_new.unwrap_or_else(Vec::new);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
++   |
++   = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
++
 +error: use of `.unwrap_or_else(..)` to construct default value
 +  --> $DIR/unwrap_or_else_default.rs:62:5
 +   |
 +LL |     with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
- error: aborting due to 3 previous errors
 +
 +error: use of `.unwrap_or_else(..)` to construct default value
 +  --> $DIR/unwrap_or_else_default.rs:65:5
 +   |
 +LL |     with_default_trait.unwrap_or_else(Default::default);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
 +
 +error: use of `.unwrap_or_else(..)` to construct default value
 +  --> $DIR/unwrap_or_else_default.rs:68:5
 +   |
 +LL |     with_default_type.unwrap_or_else(u64::default);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
 +
++error: use of `.unwrap_or_else(..)` to construct default value
++  --> $DIR/unwrap_or_else_default.rs:71:5
++   |
++LL |     with_default_type.unwrap_or_else(Vec::new);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
++
++error: aborting due to 5 previous errors
 +