]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '3d0b0e66afdfaa519d8855b338b35b4605775945' into clippyup
authorflip1995 <hello@philkrones.com>
Fri, 28 Aug 2020 14:10:16 +0000 (16:10 +0200)
committerflip1995 <hello@philkrones.com>
Fri, 28 Aug 2020 16:43:25 +0000 (18:43 +0200)
153 files changed:
1  2 
src/tools/clippy/.cargo/config
src/tools/clippy/.github/workflows/clippy.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/Cargo.toml
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/assign_ops.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/double_comparison.rs
src/tools/clippy/clippy_lints/src/duration_subsec.rs
src/tools/clippy/clippy_lints/src/enum_clike.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/if_let_some_result.rs
src/tools/clippy/clippy_lints/src/if_not_else.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
src/tools/clippy/clippy_lints/src/inherent_impl.rs
src/tools/clippy/clippy_lints/src/int_plus_one.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops.rs
src/tools/clippy/clippy_lints/src/map_clone.rs
src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/mut_reference.rs
src/tools/clippy/clippy_lints/src/mutex_atomic.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/precedence.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
src/tools/clippy/clippy_lints/src/repeat_once.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/self_assignment.rs
src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
src/tools/clippy/clippy_lints/src/swap.rs
src/tools/clippy/clippy_lints/src/to_string_in_display.rs
src/tools/clippy/clippy_lints/src/transmute.rs
src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
src/tools/clippy/clippy_lints/src/try_err.rs
src/tools/clippy/clippy_lints/src/types.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/unused_unit.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/useless_conversion.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/higher.rs
src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/mod.rs
src/tools/clippy/clippy_lints/src/utils/paths.rs
src/tools/clippy/clippy_lints/src/vec.rs
src/tools/clippy/clippy_lints/src/wildcard_imports.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/doc/adding_lints.md
src/tools/clippy/src/lintlist/mod.rs
src/tools/clippy/tests/fmt.rs
src/tools/clippy/tests/ui/auxiliary/wildcard_imports_helper.rs
src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
src/tools/clippy/tests/ui/crashes/ice-5944.rs
src/tools/clippy/tests/ui/duration_subsec.stderr
src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr
src/tools/clippy/tests/ui/enum_variants.stderr
src/tools/clippy/tests/ui/float_equality_without_abs.rs
src/tools/clippy/tests/ui/float_equality_without_abs.stderr
src/tools/clippy/tests/ui/if_let_some_result.stderr
src/tools/clippy/tests/ui/if_not_else.stderr
src/tools/clippy/tests/ui/impl.stderr
src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
src/tools/clippy/tests/ui/int_plus_one.stderr
src/tools/clippy/tests/ui/iter_next_slice.stderr
src/tools/clippy/tests/ui/len_zero.fixed
src/tools/clippy/tests/ui/len_zero.rs
src/tools/clippy/tests/ui/len_zero_ranges.fixed
src/tools/clippy/tests/ui/len_zero_ranges.rs
src/tools/clippy/tests/ui/len_zero_ranges.stderr
src/tools/clippy/tests/ui/let_and_return.rs
src/tools/clippy/tests/ui/let_and_return.stderr
src/tools/clippy/tests/ui/map_clone.stderr
src/tools/clippy/tests/ui/methods.rs
src/tools/clippy/tests/ui/methods.stderr
src/tools/clippy/tests/ui/mut_reference.stderr
src/tools/clippy/tests/ui/mutex_atomic.stderr
src/tools/clippy/tests/ui/needless_doc_main.rs
src/tools/clippy/tests/ui/needless_doc_main.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/new_ret_no_self.rs
src/tools/clippy/tests/ui/new_ret_no_self.stderr
src/tools/clippy/tests/ui/option_as_ref_deref.fixed
src/tools/clippy/tests/ui/option_as_ref_deref.rs
src/tools/clippy/tests/ui/option_as_ref_deref.stderr
src/tools/clippy/tests/ui/precedence.fixed
src/tools/clippy/tests/ui/precedence.rs
src/tools/clippy/tests/ui/precedence.stderr
src/tools/clippy/tests/ui/redundant_allocation.fixed
src/tools/clippy/tests/ui/redundant_allocation.stderr
src/tools/clippy/tests/ui/redundant_closure_call_early.stderr
src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
src/tools/clippy/tests/ui/redundant_closure_call_late.rs
src/tools/clippy/tests/ui/same_item_push.rs
src/tools/clippy/tests/ui/self_assignment.rs
src/tools/clippy/tests/ui/self_assignment.stderr
src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
src/tools/clippy/tests/ui/single_char_push_str.fixed
src/tools/clippy/tests/ui/single_char_push_str.rs
src/tools/clippy/tests/ui/single_char_push_str.stderr
src/tools/clippy/tests/ui/stable_sort_primitive.stderr
src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs
src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr
src/tools/clippy/tests/ui/to_string_in_display.rs
src/tools/clippy/tests/ui/to_string_in_display.stderr
src/tools/clippy/tests/ui/transmute.rs
src/tools/clippy/tests/ui/transmute.stderr
src/tools/clippy/tests/ui/transmute_float_to_int.rs
src/tools/clippy/tests/ui/transmute_float_to_int.stderr
src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
src/tools/clippy/tests/ui/unnecessary_clone.rs
src/tools/clippy/tests/ui/unnecessary_clone.stderr
src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
src/tools/clippy/tests/ui/unwrap_in_result.rs
src/tools/clippy/tests/ui/unwrap_in_result.stderr
src/tools/clippy/tests/ui/useless_conversion.fixed
src/tools/clippy/tests/ui/useless_conversion.rs
src/tools/clippy/tests/ui/useless_conversion.stderr
src/tools/clippy/tests/ui/vec.fixed
src/tools/clippy/tests/ui/vec.rs
src/tools/clippy/tests/ui/wildcard_imports.fixed
src/tools/clippy/tests/ui/wildcard_imports.rs
src/tools/clippy/tests/ui/wildcard_imports.stderr
src/tools/clippy/tests/ui/wrong_self_convention.rs
src/tools/clippy/tests/ui/wrong_self_convention.stderr

index 2bad3b9c57f0c95f05d5071bd0c45560f55c88a5,0000000000000000000000000000000000000000..e70da43ab47abe45cb278e82216729723d7d37b0
mode 100644,000000..100644
--- /dev/null
@@@ -1,6 -1,0 +1,6 @@@
- dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
 +[alias]
 +uitest = "test --test compile-test"
++dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
 +
 +[build]
 +rustflags = ["-Zunstable-options"]
index 5fa8009a8b42c8fad795d61114ad70deacdcd5fc,0000000000000000000000000000000000000000..99e371631b149bbef1b7f537fbfd19fcc20eb982
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,106 @@@
 +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:
 +    runs-on: ubuntu-latest
 +
 +    steps:
 +    # Setup
 +    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
 +      with:
 +        github_token: "${{ secrets.github_token }}"
 +
 +    - name: rust-toolchain
 +      uses: actions-rs/toolchain@v1.0.3
 +      with:
 +        toolchain: nightly
 +        target: x86_64-unknown-linux-gnu
 +        profile: minimal
 +
 +    - name: Checkout
 +      uses: actions/checkout@v2.0.0
 +
 +    - name: Run cargo update
 +      run: cargo update
 +
 +    - name: Cache cargo dir
 +      uses: actions/cache@v2
 +      with:
 +        path: ~/.cargo
 +        key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }}
 +        restore-keys: |
 +          ${{ runner.os }}-x86_64-unknown-linux-gnu
 +
 +    - name: Master Toolchain Setup
 +      run: bash setup-toolchain.sh
 +
 +    # Run
 +    - name: Set LD_LIBRARY_PATH (Linux)
 +      run: |
 +        SYSROOT=$(rustc --print sysroot)
 +        echo "::set-env name=LD_LIBRARY_PATH::${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}"
 +
 +    - name: Build
 +      run: cargo build --features deny-warnings
 +
 +    - name: Test
 +      run: cargo test --features deny-warnings
 +
 +    - name: Test clippy_lints
 +      run: cargo test --features deny-warnings
 +      working-directory: clippy_lints
 +
 +    - 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 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
++
 +    # Cleanup
 +    - name: Run cargo-cache --autoclean
 +      run: |
 +        cargo +nightly install cargo-cache --no-default-features --features ci-autoclean cargo-cache
 +        cargo cache
index 5e9ed54c848205e499dd85cb43146d9b1d3f6f1e,0000000000000000000000000000000000000000..137b561028a658fae51e18d0a5a16601a1a66e9c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1810 -1,0 +1,1816 @@@
 +# 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
 +
 +[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master)
 +
 +## Rust 1.46
 +
 +Current beta, release 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
 +
 +Current stable, 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`],
 +  [`mem_discriminant_non_enum`], [`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
 +
 +<!-- 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
 +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 +[`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_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_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
 +[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 +[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 +[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
 +[`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
 +[`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_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`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_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
 +[`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
 +[`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_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_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
 +[`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
 +[`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
 +[`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
 +[`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_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
 +[`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_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
 +[`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_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`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
 +[`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
 +[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
 +[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`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_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_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
 +[`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_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_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`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_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 +[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 +[`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_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 +[`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_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_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 +[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
 +[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 +[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 +[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 +[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 +[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 +[`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_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_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
 +[`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_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_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_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`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_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
 +[`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
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`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
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`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_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_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`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_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_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
 +[`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_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_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 +[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 +[`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
 +[`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
 +[`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
 +[`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_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
++[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_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
 +[`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_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`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_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
 +[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
++[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 +[`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
 +[`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_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
 +[`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
 +[`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_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 +[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_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_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`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_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_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 +[`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
++[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
 +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 +[`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_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_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index 5f7b1e85ee9a1769f6de383ca49bd5c433e47293,0000000000000000000000000000000000000000..54777810abbdfac70346b952f2510388aa1e789c
mode 100644,000000..100644
--- /dev/null
@@@ -1,296 -1,0 +1,336 @@@
- 4. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy:
 +# 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 [Discord].
 +
 +All contributors are expected to follow the [Rust Code of Conduct].
 +
 +- [Contributing to Clippy](#contributing-to-clippy)
 +  - [Getting started](#getting-started)
 +    - [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)
 +  - [How Clippy works](#how-clippy-works)
 +  - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust)
 +  - [Issue and PR triage](#issue-and-pr-triage)
 +  - [Bors and Homu](#bors-and-homu)
 +  - [Contributions](#contributions)
 +
 +[Discord]: https://discord.gg/rust-lang
 +[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 with a bug just ask
 +@Manishearth, @flip1995, @phansch or @yaahc.
 +
 +Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues.
 +If you want to work on an issue, please leave a comment so that we can assign it to you!
 +
 +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 E-easy issue first.
 +They are mostly classified as [`E-medium`], since they might be somewhat involved code wise,
 +but not difficult per-se.
 +
 +[`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%20first%20issue
 +[`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
 +
 +Unfortunately, [`rust-analyzer`][ra_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 rust-analyzer will be able to understand.
 +Run `cargo dev ra-setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo
 +you just cloned.
 +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
 +Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses.
 +Just make sure to remove the dependencies again before finally making a pull request!
 +
 +[ra_homepage]: https://rust-analyzer.github.io/
 +[rustc_repo]: https://github.com/rust-lang/rust/
 +
 +## 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
 +
 +## Fixing build failures caused by Rust
 +
 +Clippy currently gets built with `rustc` of the `rust-lang/rust` `master`
 +branch. Most of the times we have to adapt to the changes and only very rarely
 +there's an actual bug in Rust.
 +
 +If you decide to make Clippy work again with a Rust commit that breaks it, you
 +have to sync the `rust-lang/rust-clippy` repository with the `subtree` copy of
 +Clippy in the `rust-lang/rust` repository.
 +
 +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
++
 +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
 +2. 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
 +    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
 +    ```
 +3. 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 [Discord] channel.)
- 5. Open a PR to [`rust-lang/rust`]
++   
++### Syncing back changes in Clippy to [`rust-lang/rust`]
++
++To avoid flooding the [`rust-lang/rust`] PR queue, changes in Clippy's repo are synced back
++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
++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.
++
++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
 +    ```
- Also, you may want to define remotes, so you don't have to type out the remote
++3. Open a PR to [`rust-lang/rust`]
++
++### Defining remotes
 +
- _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`. For
- this to work, you will need the fix of `git subtree` available
- [here][gitgitgadget-pr].
++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]. 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.
 +
 +## 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%20%3Aboom%3A
 +[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug%20%3Abeetle%3A
 +[homu]: https://github.com/rust-lang/homu
 +[homu_instructions]: https://buildbot2.rust-lang.org/homu/
 +[homu_queue]: https://buildbot2.rust-lang.org/homu/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 836897927b01530d8227ce135a433c9168829d50,0000000000000000000000000000000000000000..c7a3099b8ab0a4f0857cce4b5d079b359a27e85e
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- semver = "0.9"
 +[package]
 +name = "clippy"
 +version = "0.0.212"
 +authors = [
 +      "Manish Goregaokar <manishsmail@gmail.com>",
 +      "Andre Bogus <bogusandre@gmail.com>",
 +      "Georg Brandl <georg@python.org>",
 +      "Martin Carton <cartonmartin@gmail.com>",
 +      "Oliver Schneider <clippy-iethah7aipeen8neex1a@oli-obk.de>"
 +]
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +categories = ["development-tools", "development-tools::cargo-plugins"]
 +build = "build.rs"
 +edition = "2018"
 +publish = false
 +
 +[[bin]]
 +name = "cargo-clippy"
 +test = false
 +path = "src/main.rs"
 +
 +[[bin]]
 +name = "clippy-driver"
 +path = "src/driver.rs"
 +
 +[dependencies]
 +# begin automatic update
 +clippy_lints = { version = "0.0.212", path = "clippy_lints" }
 +# end automatic update
- cargo_metadata = "0.9.1"
++semver = "0.10"
 +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
 +tempfile = { version = "3.1.0", optional = true }
 +lazy_static = "1.0"
 +
 +[dev-dependencies]
++cargo_metadata = "0.11.1"
 +compiletest_rs = { version = "0.5.0", features = ["tmp"] }
 +tester = "0.7"
 +lazy_static = "1.0"
 +clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
 +serde = { version = "1.0", features = ["derive"] }
 +derive-new = "0.5"
 +
 +# A noop dependency that changes in the Rust repository, it's a bit of a hack.
 +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
 +# for more information.
 +rustc-workspace-hack = "1.0.0"
 +
 +[build-dependencies]
 +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
 +
 +[features]
 +deny-warnings = []
 +integration = ["tempfile"]
index 1e032a7bc20cde319cd7442e4d5360d4285f2232,0000000000000000000000000000000000000000..d951ca0e6308d154d8d121b8bf1880067656015d
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,219 @@@
-         "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
 +use crate::clippy_project_root;
 +use std::fs::{self, OpenOptions};
 +use std::io::prelude::*;
 +use std::io::{self, ErrorKind};
 +use std::path::{Path, PathBuf};
 +
 +struct LintData<'a> {
 +    pass: &'a str,
 +    name: &'a str,
 +    category: &'a str,
 +    project_root: PathBuf,
 +}
 +
 +trait Context {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self;
 +}
 +
 +impl<T> Context for io::Result<T> {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self {
 +        match self {
 +            Ok(t) => Ok(t),
 +            Err(e) => {
 +                let message = format!("{}: {}", text.as_ref(), e);
 +                Err(io::Error::new(ErrorKind::Other, message))
 +            },
 +        }
 +    }
 +}
 +
 +/// Creates the files required to implement and test a new lint and runs `update_lints`.
 +///
 +/// # Errors
 +///
 +/// This function errors out if the files couldn't be created or written to.
 +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> {
 +    let lint = LintData {
 +        pass: pass.expect("`pass` argument is validated by clap"),
 +        name: lint_name.expect("`name` argument is validated by clap"),
 +        category: category.expect("`category` argument is validated by clap"),
 +        project_root: clippy_project_root(),
 +    };
 +
 +    create_lint(&lint).context("Unable to create lint implementation")?;
 +    create_test(&lint).context("Unable to create a test for the new lint")
 +}
 +
 +fn create_lint(lint: &LintData) -> io::Result<()> {
 +    let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
 +        "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
++        "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
 +        _ => {
 +            unreachable!("`pass_type` should only ever be `early` or `late`!");
 +        },
 +    };
 +
 +    let camel_case_name = to_camel_case(lint.name);
 +    let lint_contents = get_lint_file_contents(
 +        pass_type,
 +        pass_lifetimes,
 +        lint.name,
 +        &camel_case_name,
 +        lint.category,
 +        pass_import,
 +        context_import,
 +    );
 +
 +    let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
 +    write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
 +}
 +
 +fn create_test(lint: &LintData) -> io::Result<()> {
 +    fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
 +        let mut path = location.into().join(case);
 +        fs::create_dir(&path)?;
 +        write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
 +
 +        path.push("src");
 +        fs::create_dir(&path)?;
 +        let header = format!("// compile-flags: --crate-name={}", lint_name);
 +        write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
 +
 +        Ok(())
 +    }
 +
 +    if lint.category == "cargo" {
 +        let relative_test_dir = format!("tests/ui-cargo/{}", lint.name);
 +        let test_dir = lint.project_root.join(relative_test_dir);
 +        fs::create_dir(&test_dir)?;
 +
 +        create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
 +        create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")
 +    } else {
 +        let test_path = format!("tests/ui/{}.rs", lint.name);
 +        let test_contents = get_test_file_contents(lint.name, None);
 +        write_file(lint.project_root.join(test_path), test_contents)
 +    }
 +}
 +
 +fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
 +    fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
 +        OpenOptions::new()
 +            .write(true)
 +            .create_new(true)
 +            .open(path)?
 +            .write_all(contents)
 +    }
 +
 +    inner(path.as_ref(), contents.as_ref()).context(format!("writing to file: {}", path.as_ref().display()))
 +}
 +
 +fn to_camel_case(name: &str) -> String {
 +    name.split('_')
 +        .map(|s| {
 +            if s.is_empty() {
 +                String::from("")
 +            } else {
 +                [&s[0..1].to_uppercase(), &s[1..]].concat()
 +            }
 +        })
 +        .collect()
 +}
 +
 +fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
 +    let mut contents = format!(
 +        "#![warn(clippy::{})]
 +
 +fn main() {{
 +    // test code goes here
 +}}
 +",
 +        lint_name
 +    );
 +
 +    if let Some(header) = header_commands {
 +        contents = format!("{}\n{}", header, contents);
 +    }
 +
 +    contents
 +}
 +
 +fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
 +    format!(
 +        r#"
 +# {}
 +
 +[package]
 +name = "{}"
 +version = "0.1.0"
 +publish = false
 +
 +[workspace]
 +"#,
 +        hint, lint_name
 +    )
 +}
 +
 +fn get_lint_file_contents(
 +    pass_type: &str,
 +    pass_lifetimes: &str,
 +    lint_name: &str,
 +    camel_case_name: &str,
 +    category: &str,
 +    pass_import: &str,
 +    context_import: &str,
 +) -> String {
 +    format!(
 +        "use rustc_lint::{{{type}, {context_import}}};
 +use rustc_session::{{declare_lint_pass, declare_tool_lint}};
 +{pass_import}
 +
 +declare_clippy_lint! {{
 +    /// **What it does:**
 +    ///
 +    /// **Why is this bad?**
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // example code which does not raise clippy warning
 +    /// ```
 +    pub {name_upper},
 +    {category},
 +    \"default lint description\"
 +}}
 +
 +declare_lint_pass!({name_camel} => [{name_upper}]);
 +
 +impl {type}{lifetimes} for {name_camel} {{}}
 +",
 +        type=pass_type,
 +        lifetimes=pass_lifetimes,
 +        name_upper=lint_name.to_uppercase(),
 +        name_camel=camel_case_name,
 +        category=category,
 +        pass_import=pass_import,
 +        context_import=context_import
 +    )
 +}
 +
 +#[test]
 +fn test_camel_case() {
 +    let s = "a_lint";
 +    let s2 = to_camel_case(s);
 +    assert_eq!(s2, "ALint");
 +
 +    let name = "a_really_long_new_lint";
 +    let name2 = to_camel_case(name);
 +    assert_eq!(name2, "AReallyLongNewLint");
 +
 +    let name3 = "lint__name";
 +    let name4 = to_camel_case(name3);
 +    assert_eq!(name4, "LintName");
 +}
index e959c1a65112286fc14688e20c3906be95a69d23,0000000000000000000000000000000000000000..cc7d3a04f003ee0728feb89aa83ef147fe12e7ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,39 @@@
- cargo_metadata = "0.9.1"
 +[package]
 +name = "clippy_lints"
 +# begin automatic update
 +version = "0.0.212"
 +# end automatic update
 +authors = [
 +      "Manish Goregaokar <manishsmail@gmail.com>",
 +      "Andre Bogus <bogusandre@gmail.com>",
 +      "Georg Brandl <georg@python.org>",
 +      "Martin Carton <cartonmartin@gmail.com>"
 +]
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +edition = "2018"
 +
 +[dependencies]
- semver = "0.9.0"
++cargo_metadata = "0.11.1"
 +if_chain = "1.0.0"
 +itertools = "0.9"
 +lazy_static = "1.0.2"
 +pulldown-cmark = { version = "0.7.1", default-features = false }
 +quine-mc_cluskey = "0.2.2"
 +regex-syntax = "0.6"
 +serde = { version = "1.0", features = ["derive"] }
 +smallvec = { version = "1", features = ["union"] }
 +toml = "0.5.3"
 +unicode-normalization = "0.1"
++semver = "0.10.0"
 +# NOTE: cargo requires serde feat in its url dep
 +# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
 +url = { version =  "2.1.0", features = ["serde"] }
 +quote = "1"
 +syn = { version = "1", features = ["full"] }
 +
 +[features]
 +deny-warnings = []
index dab1e96e282f051c75f8184b718f745fb711cace,0000000000000000000000000000000000000000..b3185b88840142253648eb1eb033dca657d20aa6
mode 100644,000000..100644
--- /dev/null
@@@ -1,265 -1,0 +1,263 @@@
-     get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq,
 +use crate::utils::{
-                     if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
++    eq_expr_value, get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method,
 +};
 +use crate::utils::{higher, sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
 +    /// patterns.
 +    ///
 +    /// **Why is this bad?** These can be written as the shorter `a op= b`.
 +    ///
 +    /// **Known problems:** While forbidden by the spec, `OpAssign` traits may have
 +    /// implementations that differ from the regular `Op` impl.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let mut a = 5;
 +    /// let b = 0;
 +    /// // ...
 +    /// // Bad
 +    /// a = a + b;
 +    ///
 +    /// // Good
 +    /// a += b;
 +    /// ```
 +    pub ASSIGN_OP_PATTERN,
 +    style,
 +    "assigning the result of an operation on a variable to that same variable"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns.
 +    ///
 +    /// **Why is this bad?** Most likely these are bugs where one meant to write `a
 +    /// op= b`.
 +    ///
 +    /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have
 +    /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
 +    /// If `a op= a op b` is really the correct behaviour it should be
 +    /// written as `a = a op a op b` as it's less confusing.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let mut a = 5;
 +    /// let b = 2;
 +    /// // ...
 +    /// a += a + b;
 +    /// ```
 +    pub MISREFACTORED_ASSIGN_OP,
 +    complexity,
 +    "having a variable on both sides of an assign op"
 +}
 +
 +declare_lint_pass!(AssignOps => [ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for AssignOps {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        match &expr.kind {
 +            hir::ExprKind::AssignOp(op, lhs, rhs) => {
 +                if let hir::ExprKind::Binary(binop, l, r) = &rhs.kind {
 +                    if op.node != binop.node {
 +                        return;
 +                    }
 +                    // lhs op= l op r
-                     if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
++                    if eq_expr_value(cx, lhs, l) {
 +                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r);
 +                    }
 +                    // lhs op= l commutative_op r
-                         if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
++                    if is_commutative(op.node) && eq_expr_value(cx, lhs, r) {
 +                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l);
 +                    }
 +                }
 +            },
 +            hir::ExprKind::Assign(assignee, e, _) => {
 +                if let hir::ExprKind::Binary(op, l, r) = &e.kind {
 +                    let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
 +                        let ty = cx.typeck_results().expr_ty(assignee);
 +                        let rty = cx.typeck_results().expr_ty(rhs);
 +                        macro_rules! ops {
 +                            ($op:expr,
 +                             $cx:expr,
 +                             $ty:expr,
 +                             $rty:expr,
 +                             $($trait_name:ident),+) => {
 +                                match $op {
 +                                    $(hir::BinOpKind::$trait_name => {
 +                                        let [krate, module] = crate::utils::paths::OPS_MODULE;
 +                                        let path: [&str; 3] = [krate, module, concat!(stringify!($trait_name), "Assign")];
 +                                        let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) {
 +                                            trait_id
 +                                        } else {
 +                                            return; // useless if the trait doesn't exist
 +                                        };
 +                                        // check that we are not inside an `impl AssignOp` of this exact operation
 +                                        let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
 +                                        if_chain! {
 +                                            if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
 +                                            if trait_ref.path.res.def_id() == trait_id;
 +                                            then { return; }
 +                                        }
 +                                        implements_trait($cx, $ty, trait_id, &[$rty])
 +                                    },)*
 +                                    _ => false,
 +                                }
 +                            }
 +                        }
 +                        if ops!(
 +                            op.node,
 +                            cx,
 +                            ty,
 +                            rty.into(),
 +                            Add,
 +                            Sub,
 +                            Mul,
 +                            Div,
 +                            Rem,
 +                            And,
 +                            Or,
 +                            BitAnd,
 +                            BitOr,
 +                            BitXor,
 +                            Shr,
 +                            Shl
 +                        ) {
 +                            span_lint_and_then(
 +                                cx,
 +                                ASSIGN_OP_PATTERN,
 +                                expr.span,
 +                                "manual implementation of an assign operation",
 +                                |diag| {
 +                                    if let (Some(snip_a), Some(snip_r)) =
 +                                        (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
 +                                    {
 +                                        diag.span_suggestion(
 +                                            expr.span,
 +                                            "replace it with",
 +                                            format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
 +                                            Applicability::MachineApplicable,
 +                                        );
 +                                    }
 +                                },
 +                            );
 +                        }
 +                    };
 +
 +                    let mut visitor = ExprVisitor {
 +                        assignee,
 +                        counter: 0,
 +                        cx,
 +                    };
 +
 +                    walk_expr(&mut visitor, e);
 +
 +                    if visitor.counter == 1 {
 +                        // a = a op b
-                         if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
-                             && cx.typeck_results().expr_ty(assignee).is_primitive_ty()
-                         {
++                        if eq_expr_value(cx, assignee, l) {
 +                            lint(assignee, r);
 +                        }
 +                        // a = b commutative_op a
 +                        // Limited to primitive type as these ops are know to be commutative
-         if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, expr) {
++                        if eq_expr_value(cx, assignee, r) && cx.typeck_results().expr_ty(assignee).is_primitive_ty() {
 +                            match op.node {
 +                                hir::BinOpKind::Add
 +                                | hir::BinOpKind::Mul
 +                                | hir::BinOpKind::And
 +                                | hir::BinOpKind::Or
 +                                | hir::BinOpKind::BitXor
 +                                | hir::BinOpKind::BitAnd
 +                                | hir::BinOpKind::BitOr => {
 +                                    lint(assignee, l);
 +                                },
 +                                _ => {},
 +                            }
 +                        }
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +fn lint_misrefactored_assign_op(
 +    cx: &LateContext<'_>,
 +    expr: &hir::Expr<'_>,
 +    op: hir::BinOp,
 +    rhs: &hir::Expr<'_>,
 +    assignee: &hir::Expr<'_>,
 +    rhs_other: &hir::Expr<'_>,
 +) {
 +    span_lint_and_then(
 +        cx,
 +        MISREFACTORED_ASSIGN_OP,
 +        expr.span,
 +        "variable appears on both sides of an assignment operation",
 +        |diag| {
 +            if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
 +                let a = &sugg::Sugg::hir(cx, assignee, "..");
 +                let r = &sugg::Sugg::hir(cx, rhs, "..");
 +                let long = format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
 +                diag.span_suggestion(
 +                    expr.span,
 +                    &format!(
 +                        "Did you mean `{} = {} {} {}` or `{}`? Consider replacing it with",
 +                        snip_a,
 +                        snip_a,
 +                        op.node.as_str(),
 +                        snip_r,
 +                        long
 +                    ),
 +                    format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
 +                    Applicability::MaybeIncorrect,
 +                );
 +                diag.span_suggestion(
 +                    expr.span,
 +                    "or",
 +                    long,
 +                    Applicability::MaybeIncorrect, // snippet
 +                );
 +            }
 +        },
 +    );
 +}
 +
 +#[must_use]
 +fn is_commutative(op: hir::BinOpKind) -> bool {
 +    use rustc_hir::BinOpKind::{
 +        Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
 +    };
 +    match op {
 +        Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true,
 +        Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false,
 +    }
 +}
 +
 +struct ExprVisitor<'a, 'tcx> {
 +    assignee: &'a hir::Expr<'a>,
 +    counter: u8,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
++        if eq_expr_value(self.cx, self.assignee, expr) {
 +            self.counter += 1;
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index 76ccf2e4bb98b0f37febdd73a133dcae08c2c952,0000000000000000000000000000000000000000..cfcc1b3c5f356948df9bb333ccc292dd7a12e06e
mode 100644,000000..100644
--- /dev/null
@@@ -1,711 -1,0 +1,711 @@@
- use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 +//! checks for attributes
 +
 +use crate::utils::{
 +    first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help,
 +    span_lint_and_sugg, span_lint_and_then, without_block_comments,
 +};
 +use if_chain::if_chain;
 +use rustc_ast::util::lev_distance::find_best_match_for_name;
++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::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{Symbol, SymbolStr};
 +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] = &["cloudabi", "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(..) { ... }
 +    /// ```
 +    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)]` and
 +    /// `#[allow(unreachable_pub)]` 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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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;
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// #[deprecated(since = "forever")]
 +    /// fn something_else() { /* ... */ }
 +    /// ```
 +    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)
 +    /// #![inline(always)]
 +    ///
 +    /// fn this_is_fine() { }
 +    ///
 +    /// // Bad
 +    /// #[inline(always)]
 +    ///
 +    /// fn not_quite_good_code() { }
 +    ///
 +    /// // Good (as outer attribute)
 +    /// #[inline(always)]
 +    /// fn this_is_fine_too() { }
 +    /// ```
 +    pub EMPTY_LINE_AFTER_OUTER_ATTR,
 +    nursery,
 +    "empty line after outer attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `allow`/`warn`/`deny`/`forbid` attributes with scoped clippy
 +    /// lints and if those lints exist in clippy. If there is an uppercase letter in the lint name
 +    /// (not the tool name) and a lowercase version of this lint exists, it will suggest to lowercase
 +    /// the lint name.
 +    ///
 +    /// **Why is this bad?** A lint attribute with a mistyped lint name won't have an effect.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust
 +    /// #![warn(if_not_els)]
 +    /// #![deny(clippy::All)]
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #![warn(if_not_else)]
 +    /// #![deny(clippy::all)]
 +    /// ```
 +    pub UNKNOWN_CLIPPY_LINTS,
 +    style,
 +    "unknown_lints for scoped Clippy lints"
 +}
 +
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust
 +    /// #![deny(clippy::restriction)]
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #![deny(clippy::as_conversions)]
 +    /// ```
 +    pub BLANKET_CLIPPY_RESTRICTION_LINTS,
 +    style,
 +    "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() { }
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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.
 +    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,
 +    UNKNOWN_CLIPPY_LINTS,
 +    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() {
 +                let ident = &*ident.as_str();
 +                match ident {
 +                    "allow" | "warn" | "deny" | "forbid" => {
 +                        check_clippy_lint_names(cx, ident, 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<'_>) {
 +        if is_relevant_item(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, &item.attrs)
 +        }
 +        match item.kind {
 +            ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
 +                let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use)));
 +
 +                for attr in item.attrs {
 +                    if in_external_macro(cx.sess(), attr.span) {
 +                        return;
 +                    }
 +                    if let Some(lint_list) = &attr.meta_item_list() {
 +                        if let Some(ident) = attr.ident() {
 +                            match &*ident.as_str() {
 +                                "allow" | "warn" | "deny" | "forbid" => {
 +                                    // permit `unused_imports`, `deprecated` and `unreachable_pub` 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))
 +                                                {
 +                                                    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, &item.attrs)
 +        }
 +    }
 +
 +    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, &item.attrs)
 +        }
 +    }
 +}
 +
 +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
 +    fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> {
 +        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.as_str() == "clippy";
 +            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
 +            then {
 +                return Some(lint_name.as_str());
 +            }
 +        }
 +        None
 +    }
 +
 +    let lint_store = cx.lints();
 +    for lint in items {
 +        if let Some(lint_name) = extract_name(lint) {
 +            if let CheckLintNameResult::Tool(Err((None, _))) =
 +                lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
 +            {
 +                span_lint_and_then(
 +                    cx,
 +                    UNKNOWN_CLIPPY_LINTS,
 +                    lint.span(),
 +                    &format!("unknown clippy lint: clippy::{}", lint_name),
 +                    |diag| {
 +                        let name_lower = lint_name.to_lowercase();
 +                        let symbols = lint_store
 +                            .get_lints()
 +                            .iter()
 +                            .map(|l| Symbol::intern(&l.name_lower()))
 +                            .collect::<Vec<_>>();
 +                        let sugg = find_best_match_for_name(
 +                            symbols.iter(),
 +                            Symbol::intern(&format!("clippy::{}", name_lower)),
 +                            None,
 +                        );
 +                        if lint_name.chars().any(char::is_uppercase)
 +                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok()
 +                        {
 +                            diag.span_suggestion(
 +                                lint.span(),
 +                                "lowercase the lint name",
 +                                format!("clippy::{}", name_lower),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        } else if let Some(sugg) = sugg {
 +                            diag.span_suggestion(
 +                                lint.span(),
 +                                "did you mean",
 +                                sugg.to_string(),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    },
 +                );
 +            } else if lint_name == "restriction" && ident != "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),
 +            _ => 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_def_path(cx, fun_id, &paths::BEGIN_PANIC))
 +            } 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
 +    }
 +}
 +
 +declare_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);
 +        check_mismatched_target_os(cx, attr);
 +    }
 +}
 +
 +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());
 +            let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt());
 +
 +            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) {
 +    if_chain! {
 +        // 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 let AttrStyle::Outer = attr.style;
 +        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));
 +                            }
 +                        }
 +                    },
 +                    _ => {},
 +                }
 +            }
 +        }
 +
 +        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;
 +                    }
 +                }
 +            });
 +        }
 +    }
 +}
index 18529f2113e77bc16a36b798f3a71ac1539c2917,0000000000000000000000000000000000000000..280a2c7fe6770c68987354a8c7bfc7f8c527ef02
mode 100644,000000..100644
--- /dev/null
@@@ -1,503 -1,0 +1,503 @@@
-     get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, span_lint_and_sugg,
-     span_lint_and_then, SpanlessEq,
 +use crate::utils::{
-             if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) {
++    eq_expr_value, get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt,
++    span_lint_and_sugg, span_lint_and_then,
 +};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for boolean expressions that can be written more
 +    /// concisely.
 +    ///
 +    /// **Why is this bad?** Readability of boolean expressions suffers from
 +    /// unnecessary duplication.
 +    ///
 +    /// **Known problems:** Ignores short circuiting behavior of `||` and
 +    /// `&&`. Ignores `|`, `&` and `^`.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if a && true  // should be: if a
 +    /// if !(a == b)  // should be: if a != b
 +    /// ```
 +    pub NONMINIMAL_BOOL,
 +    complexity,
 +    "boolean expressions that can be written more concisely"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for boolean expressions that contain terminals that
 +    /// can be eliminated.
 +    ///
 +    /// **Why is this bad?** This is most likely a logic bug.
 +    ///
 +    /// **Known problems:** Ignores short circuiting behavior.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if a && b || a { ... }
 +    /// ```
 +    /// The `b` is unnecessary, the expression is equivalent to `if a`.
 +    pub LOGIC_BUG,
 +    correctness,
 +    "boolean expressions that contain terminals which can be eliminated"
 +}
 +
 +// For each pairs, both orders are considered.
 +const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
 +
 +declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
 +
 +impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        _: FnKind<'tcx>,
 +        _: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        _: Span,
 +        _: HirId,
 +    ) {
 +        NonminimalBoolVisitor { cx }.visit_body(body)
 +    }
 +}
 +
 +struct NonminimalBoolVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +use quine_mc_cluskey::Bool;
 +struct Hir2Qmm<'a, 'tcx, 'v> {
 +    terminals: Vec<&'v Expr<'v>>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
 +    fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
 +        for a in a {
 +            if let ExprKind::Binary(binop, lhs, rhs) = &a.kind {
 +                if binop.node == op {
 +                    v = self.extract(op, &[lhs, rhs], v)?;
 +                    continue;
 +                }
 +            }
 +            v.push(self.run(a)?);
 +        }
 +        Ok(v)
 +    }
 +
 +    fn run(&mut self, e: &'v Expr<'_>) -> Result<Bool, String> {
 +        fn negate(bin_op_kind: BinOpKind) -> Option<BinOpKind> {
 +            match bin_op_kind {
 +                BinOpKind::Eq => Some(BinOpKind::Ne),
 +                BinOpKind::Ne => Some(BinOpKind::Eq),
 +                BinOpKind::Gt => Some(BinOpKind::Le),
 +                BinOpKind::Ge => Some(BinOpKind::Lt),
 +                BinOpKind::Lt => Some(BinOpKind::Ge),
 +                BinOpKind::Le => Some(BinOpKind::Gt),
 +                _ => None,
 +            }
 +        }
 +
 +        // prevent folding of `cfg!` macros and the like
 +        if !e.span.from_expansion() {
 +            match &e.kind {
 +                ExprKind::Unary(UnOp::UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)),
 +                ExprKind::Binary(binop, lhs, rhs) => match &binop.node {
 +                    BinOpKind::Or => {
 +                        return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?));
 +                    },
 +                    BinOpKind::And => {
 +                        return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?));
 +                    },
 +                    _ => (),
 +                },
 +                ExprKind::Lit(lit) => match lit.node {
 +                    LitKind::Bool(true) => return Ok(Bool::True),
 +                    LitKind::Bool(false) => return Ok(Bool::False),
 +                    _ => (),
 +                },
 +                _ => (),
 +            }
 +        }
 +        for (n, expr) in self.terminals.iter().enumerate() {
-                 if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_lhs, expr_lhs);
-                 if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e_rhs, expr_rhs);
++            if eq_expr_value(self.cx, e, expr) {
 +                #[allow(clippy::cast_possible_truncation)]
 +                return Ok(Bool::Term(n as u8));
 +            }
 +
 +            if_chain! {
 +                if let ExprKind::Binary(e_binop, e_lhs, e_rhs) = &e.kind;
 +                if implements_ord(self.cx, e_lhs);
 +                if let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind;
 +                if negate(e_binop.node) == Some(expr_binop.node);
++                if eq_expr_value(self.cx, e_lhs, expr_lhs);
++                if eq_expr_value(self.cx, e_rhs, expr_rhs);
 +                then {
 +                    #[allow(clippy::cast_possible_truncation)]
 +                    return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
 +                }
 +            }
 +        }
 +        let n = self.terminals.len();
 +        self.terminals.push(e);
 +        if n < 32 {
 +            #[allow(clippy::cast_possible_truncation)]
 +            Ok(Bool::Term(n as u8))
 +        } else {
 +            Err("too many literals".to_owned())
 +        }
 +    }
 +}
 +
 +struct SuggestContext<'a, 'tcx, 'v> {
 +    terminals: &'v [&'v Expr<'v>],
 +    cx: &'a LateContext<'tcx>,
 +    output: String,
 +}
 +
 +impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
 +    fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
 +        use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
 +        match suggestion {
 +            True => {
 +                self.output.push_str("true");
 +            },
 +            False => {
 +                self.output.push_str("false");
 +            },
 +            Not(inner) => match **inner {
 +                And(_) | Or(_) => {
 +                    self.output.push('!');
 +                    self.output.push('(');
 +                    self.recurse(inner);
 +                    self.output.push(')');
 +                },
 +                Term(n) => {
 +                    let terminal = self.terminals[n as usize];
 +                    if let Some(str) = simplify_not(self.cx, terminal) {
 +                        self.output.push_str(&str)
 +                    } else {
 +                        self.output.push('!');
 +                        let snip = snippet_opt(self.cx, terminal.span)?;
 +                        self.output.push_str(&snip);
 +                    }
 +                },
 +                True | False | Not(_) => {
 +                    self.output.push('!');
 +                    self.recurse(inner)?;
 +                },
 +            },
 +            And(v) => {
 +                for (index, inner) in v.iter().enumerate() {
 +                    if index > 0 {
 +                        self.output.push_str(" && ");
 +                    }
 +                    if let Or(_) = *inner {
 +                        self.output.push('(');
 +                        self.recurse(inner);
 +                        self.output.push(')');
 +                    } else {
 +                        self.recurse(inner);
 +                    }
 +                }
 +            },
 +            Or(v) => {
 +                for (index, inner) in v.iter().rev().enumerate() {
 +                    if index > 0 {
 +                        self.output.push_str(" || ");
 +                    }
 +                    self.recurse(inner);
 +                }
 +            },
 +            &Term(n) => {
 +                let snip = snippet_opt(self.cx, self.terminals[n as usize].span)?;
 +                self.output.push_str(&snip);
 +            },
 +        }
 +        Some(())
 +    }
 +}
 +
 +fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
 +    match &expr.kind {
 +        ExprKind::Binary(binop, lhs, rhs) => {
 +            if !implements_ord(cx, lhs) {
 +                return None;
 +            }
 +
 +            match binop.node {
 +                BinOpKind::Eq => Some(" != "),
 +                BinOpKind::Ne => Some(" == "),
 +                BinOpKind::Lt => Some(" >= "),
 +                BinOpKind::Gt => Some(" <= "),
 +                BinOpKind::Le => Some(" > "),
 +                BinOpKind::Ge => Some(" < "),
 +                _ => None,
 +            }
 +            .and_then(|op| {
 +                Some(format!(
 +                    "{}{}{}",
 +                    snippet_opt(cx, lhs.span)?,
 +                    op,
 +                    snippet_opt(cx, rhs.span)?
 +                ))
 +            })
 +        },
 +        ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => {
 +            let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
 +            if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
 +                && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
 +            {
 +                return None;
 +            }
 +            METHODS_WITH_NEGATION
 +                .iter()
 +                .cloned()
 +                .flat_map(|(a, b)| vec![(a, b), (b, a)])
 +                .find(|&(a, _)| {
 +                    let path: &str = &path.ident.name.as_str();
 +                    a == path
 +                })
 +                .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn suggest(cx: &LateContext<'_>, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String {
 +    let mut suggest_context = SuggestContext {
 +        terminals,
 +        cx,
 +        output: String::new(),
 +    };
 +    suggest_context.recurse(suggestion);
 +    suggest_context.output
 +}
 +
 +fn simple_negate(b: Bool) -> Bool {
 +    use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
 +    match b {
 +        True => False,
 +        False => True,
 +        t @ Term(_) => Not(Box::new(t)),
 +        And(mut v) => {
 +            for el in &mut v {
 +                *el = simple_negate(::std::mem::replace(el, True));
 +            }
 +            Or(v)
 +        },
 +        Or(mut v) => {
 +            for el in &mut v {
 +                *el = simple_negate(::std::mem::replace(el, True));
 +            }
 +            And(v)
 +        },
 +        Not(inner) => *inner,
 +    }
 +}
 +
 +#[derive(Default)]
 +struct Stats {
 +    terminals: [usize; 32],
 +    negations: usize,
 +    ops: usize,
 +}
 +
 +fn terminal_stats(b: &Bool) -> Stats {
 +    fn recurse(b: &Bool, stats: &mut Stats) {
 +        match b {
 +            True | False => stats.ops += 1,
 +            Not(inner) => {
 +                match **inner {
 +                    And(_) | Or(_) => stats.ops += 1, // brackets are also operations
 +                    _ => stats.negations += 1,
 +                }
 +                recurse(inner, stats);
 +            },
 +            And(v) | Or(v) => {
 +                stats.ops += v.len() - 1;
 +                for inner in v {
 +                    recurse(inner, stats);
 +                }
 +            },
 +            &Term(n) => stats.terminals[n as usize] += 1,
 +        }
 +    }
 +    use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
 +    let mut stats = Stats::default();
 +    recurse(b, &mut stats);
 +    stats
 +}
 +
 +impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
 +    fn bool_expr(&self, e: &'tcx Expr<'_>) {
 +        let mut h2q = Hir2Qmm {
 +            terminals: Vec::new(),
 +            cx: self.cx,
 +        };
 +        if let Ok(expr) = h2q.run(e) {
 +            if h2q.terminals.len() > 8 {
 +                // QMC has exponentially slow behavior as the number of terminals increases
 +                // 8 is reasonable, it takes approximately 0.2 seconds.
 +                // See #825
 +                return;
 +            }
 +
 +            let stats = terminal_stats(&expr);
 +            let mut simplified = expr.simplify();
 +            for simple in Bool::Not(Box::new(expr)).simplify() {
 +                match simple {
 +                    Bool::Not(_) | Bool::True | Bool::False => {},
 +                    _ => simplified.push(Bool::Not(Box::new(simple.clone()))),
 +                }
 +                let simple_negated = simple_negate(simple);
 +                if simplified.iter().any(|s| *s == simple_negated) {
 +                    continue;
 +                }
 +                simplified.push(simple_negated);
 +            }
 +            let mut improvements = Vec::with_capacity(simplified.len());
 +            'simplified: for suggestion in &simplified {
 +                let simplified_stats = terminal_stats(suggestion);
 +                let mut improvement = false;
 +                for i in 0..32 {
 +                    // ignore any "simplifications" that end up requiring a terminal more often
 +                    // than in the original expression
 +                    if stats.terminals[i] < simplified_stats.terminals[i] {
 +                        continue 'simplified;
 +                    }
 +                    if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
 +                        span_lint_and_then(
 +                            self.cx,
 +                            LOGIC_BUG,
 +                            e.span,
 +                            "this boolean expression contains a logic bug",
 +                            |diag| {
 +                                diag.span_help(
 +                                    h2q.terminals[i].span,
 +                                    "this expression can be optimized out by applying boolean operations to the \
 +                                     outer expression",
 +                                );
 +                                diag.span_suggestion(
 +                                    e.span,
 +                                    "it would look like the following",
 +                                    suggest(self.cx, suggestion, &h2q.terminals),
 +                                    // nonminimal_bool can produce minimal but
 +                                    // not human readable expressions (#3141)
 +                                    Applicability::Unspecified,
 +                                );
 +                            },
 +                        );
 +                        // don't also lint `NONMINIMAL_BOOL`
 +                        return;
 +                    }
 +                    // if the number of occurrences of a terminal decreases or any of the stats
 +                    // decreases while none increases
 +                    improvement |= (stats.terminals[i] > simplified_stats.terminals[i])
 +                        || (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops)
 +                        || (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
 +                }
 +                if improvement {
 +                    improvements.push(suggestion);
 +                }
 +            }
 +            let nonminimal_bool_lint = |suggestions: Vec<_>| {
 +                span_lint_and_then(
 +                    self.cx,
 +                    NONMINIMAL_BOOL,
 +                    e.span,
 +                    "this boolean expression can be simplified",
 +                    |diag| {
 +                        diag.span_suggestions(
 +                            e.span,
 +                            "try",
 +                            suggestions.into_iter(),
 +                            // nonminimal_bool can produce minimal but
 +                            // not human readable expressions (#3141)
 +                            Applicability::Unspecified,
 +                        );
 +                    },
 +                );
 +            };
 +            if improvements.is_empty() {
 +                let mut visitor = NotSimplificationVisitor { cx: self.cx };
 +                visitor.visit_expr(e);
 +            } else {
 +                nonminimal_bool_lint(
 +                    improvements
 +                        .into_iter()
 +                        .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals))
 +                        .collect(),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +        if in_macro(e.span) {
 +            return;
 +        }
 +        match &e.kind {
 +            ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
 +                self.bool_expr(e)
 +            },
 +            ExprKind::Unary(UnOp::UnNot, inner) => {
 +                if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
 +                    self.bool_expr(e);
 +                } else {
 +                    walk_expr(self, e);
 +                }
 +            },
 +            _ => walk_expr(self, e),
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
 +    let ty = cx.typeck_results().expr_ty(expr);
 +    get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
 +}
 +
 +struct NotSimplificationVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Unary(UnOp::UnNot, inner) = &expr.kind {
 +            if let Some(suggestion) = simplify_not(self.cx, inner) {
 +                span_lint_and_sugg(
 +                    self.cx,
 +                    NONMINIMAL_BOOL,
 +                    expr.span,
 +                    "this boolean expression can be simplified",
 +                    "try",
 +                    suggestion,
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index 1f8bff8d71e0f33d77c8e1c3b06237196d98baf6,0000000000000000000000000000000000000000..10a64769585e543bdbfd46ae8cd59287080bfd5f
mode 100644,000000..100644
--- /dev/null
@@@ -1,413 -1,0 +1,412 @@@
- use crate::utils::{SpanlessEq, SpanlessHash};
++use crate::utils::{eq_expr_value, SpanlessEq, SpanlessHash};
 +use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then};
-     let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool =
-         &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{Ty, TyS};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::Symbol;
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for consecutive `if`s with the same condition.
 +    ///
 +    /// **Why is this bad?** This is probably a copy & paste error.
 +    ///
 +    /// **Known problems:** Hopefully none.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if a == b {
 +    ///     …
 +    /// } else if a == b {
 +    ///     …
 +    /// }
 +    /// ```
 +    ///
 +    /// Note that this lint ignores all conditions with a function call as it could
 +    /// have side effects:
 +    ///
 +    /// ```ignore
 +    /// if foo() {
 +    ///     …
 +    /// } else if foo() { // not linted
 +    ///     …
 +    /// }
 +    /// ```
 +    pub IFS_SAME_COND,
 +    correctness,
 +    "consecutive `if`s with the same condition"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for consecutive `if`s with the same function call.
 +    ///
 +    /// **Why is this bad?** This is probably a copy & paste error.
 +    /// Despite the fact that function can have side effects and `if` works as
 +    /// intended, such an approach is implicit and can be considered a "code smell".
 +    ///
 +    /// **Known problems:** Hopefully none.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if foo() == bar {
 +    ///     …
 +    /// } else if foo() == bar {
 +    ///     …
 +    /// }
 +    /// ```
 +    ///
 +    /// This probably should be:
 +    /// ```ignore
 +    /// if foo() == bar {
 +    ///     …
 +    /// } else if foo() == baz {
 +    ///     …
 +    /// }
 +    /// ```
 +    ///
 +    /// or if the original code was not a typo and called function mutates a state,
 +    /// consider move the mutation out of the `if` condition to avoid similarity to
 +    /// a copy & paste error:
 +    ///
 +    /// ```ignore
 +    /// let first = foo();
 +    /// if first == bar {
 +    ///     …
 +    /// } else {
 +    ///     let second = foo();
 +    ///     if second == bar {
 +    ///     …
 +    ///     }
 +    /// }
 +    /// ```
 +    pub SAME_FUNCTIONS_IN_IF_CONDITION,
 +    pedantic,
 +    "consecutive `if`s with the same function call"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `if/else` with the same body as the *then* part
 +    /// and the *else* part.
 +    ///
 +    /// **Why is this bad?** This is probably a copy & paste error.
 +    ///
 +    /// **Known problems:** Hopefully none.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// let foo = if … {
 +    ///     42
 +    /// } else {
 +    ///     42
 +    /// };
 +    /// ```
 +    pub IF_SAME_THEN_ELSE,
 +    correctness,
 +    "`if` with the same `then` and `else` blocks"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `match` with identical arm bodies.
 +    ///
 +    /// **Why is this bad?** This is probably a copy & paste error. If arm bodies
 +    /// are the same on purpose, you can factor them
 +    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
 +    ///
 +    /// **Known problems:** False positive possible with order dependent `match`
 +    /// (see issue
 +    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => bar(), // <= oops
 +    /// }
 +    /// ```
 +    ///
 +    /// This should probably be
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => baz(), // <= fixed
 +    /// }
 +    /// ```
 +    ///
 +    /// or if the original code was not a typo:
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar | Baz => bar(), // <= shows the intent better
 +    ///     Quz => quz(),
 +    /// }
 +    /// ```
 +    pub MATCH_SAME_ARMS,
 +    pedantic,
 +    "`match` with identical arm bodies"
 +}
 +
 +declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if !expr.span.from_expansion() {
 +            // skip ifs directly in else, it will be checked in the parent if
 +            if let Some(expr) = get_parent_expr(cx, expr) {
 +                if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) {
 +                    if else_expr.hir_id == expr.hir_id {
 +                        return;
 +                    }
 +                }
 +            }
 +
 +            let (conds, blocks) = if_sequence(expr);
 +            lint_same_then_else(cx, &blocks);
 +            lint_same_cond(cx, &conds);
 +            lint_same_fns_in_if_cond(cx, &conds);
 +            lint_match_arms(cx, expr);
 +        }
 +    }
 +}
 +
 +/// Implementation of `IF_SAME_THEN_ELSE`.
 +fn lint_same_then_else(cx: &LateContext<'_>, blocks: &[&Block<'_>]) {
 +    let eq: &dyn Fn(&&Block<'_>, &&Block<'_>) -> bool =
 +        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) };
 +
 +    if let Some((i, j)) = search_same_sequenced(blocks, eq) {
 +        span_lint_and_note(
 +            cx,
 +            IF_SAME_THEN_ELSE,
 +            j.span,
 +            "this `if` has identical blocks",
 +            Some(i.span),
 +            "same as this",
 +        );
 +    }
 +}
 +
 +/// Implementation of `IFS_SAME_COND`.
 +fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
 +    let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
 +        let mut h = SpanlessHash::new(cx);
 +        h.hash_expr(expr);
 +        h.finish()
 +    };
 +
-         if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) {
++    let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool { eq_expr_value(cx, lhs, rhs) };
 +
 +    for (i, j) in search_same(conds, hash, eq) {
 +        span_lint_and_note(
 +            cx,
 +            IFS_SAME_COND,
 +            j.span,
 +            "this `if` has the same condition as a previous `if`",
 +            Some(i.span),
 +            "same as this",
 +        );
 +    }
 +}
 +
 +/// Implementation of `SAME_FUNCTIONS_IN_IF_CONDITION`.
 +fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
 +    let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
 +        let mut h = SpanlessHash::new(cx);
 +        h.hash_expr(expr);
 +        h.finish()
 +    };
 +
 +    let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool {
 +        // Do not spawn warning if `IFS_SAME_COND` already produced it.
++        if eq_expr_value(cx, lhs, rhs) {
 +            return false;
 +        }
 +        SpanlessEq::new(cx).eq_expr(lhs, rhs)
 +    };
 +
 +    for (i, j) in search_same(conds, hash, eq) {
 +        span_lint_and_note(
 +            cx,
 +            SAME_FUNCTIONS_IN_IF_CONDITION,
 +            j.span,
 +            "this `if` has the same function call as a previous `if`",
 +            Some(i.span),
 +            "same as this",
 +        );
 +    }
 +}
 +
 +/// Implementation of `MATCH_SAME_ARMS`.
 +fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +    fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol, Ty<'tcx>>) -> bool {
 +        lhs.len() == rhs.len()
 +            && lhs
 +                .iter()
 +                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty)))
 +    }
 +
 +    if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
 +        let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
 +            let mut h = SpanlessHash::new(cx);
 +            h.hash_expr(&arm.body);
 +            h.finish()
 +        };
 +
 +        let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
 +            let min_index = usize::min(lindex, rindex);
 +            let max_index = usize::max(lindex, rindex);
 +
 +            // Arms with a guard are ignored, those can’t always be merged together
 +            // This is also the case for arms in-between each there is an arm with a guard
 +            (min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
 +                SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
 +                // all patterns should have the same bindings
 +                same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat))
 +        };
 +
 +        let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
 +        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
 +            span_lint_and_then(
 +                cx,
 +                MATCH_SAME_ARMS,
 +                j.body.span,
 +                "this `match` has identical arm bodies",
 +                |diag| {
 +                    diag.span_note(i.body.span, "same as this");
 +
 +                    // Note: this does not use `span_suggestion` on purpose:
 +                    // there is no clean way
 +                    // to remove the other arm. Building a span and suggest to replace it to ""
 +                    // makes an even more confusing error message. Also in order not to make up a
 +                    // span for the whole pattern, the suggestion is only shown when there is only
 +                    // one pattern. The user should know about `|` if they are already using it…
 +
 +                    let lhs = snippet(cx, i.pat.span, "<pat1>");
 +                    let rhs = snippet(cx, j.pat.span, "<pat2>");
 +
 +                    if let PatKind::Wild = j.pat.kind {
 +                        // if the last arm is _, then i could be integrated into _
 +                        // note that i.pat cannot be _, because that would mean that we're
 +                        // hiding all the subsequent arms, and rust won't compile
 +                        diag.span_note(
 +                            i.body.span,
 +                            &format!(
 +                                "`{}` has the same arm body as the `_` wildcard, consider removing it",
 +                                lhs
 +                            ),
 +                        );
 +                    } else {
 +                        diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
 +                    }
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +/// Returns the list of bindings in a pattern.
 +fn bindings<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> FxHashMap<Symbol, Ty<'tcx>> {
 +    fn bindings_impl<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
 +        match pat.kind {
 +            PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
 +            PatKind::TupleStruct(_, pats, _) => {
 +                for pat in pats {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Binding(.., ident, ref as_pat) => {
 +                if let Entry::Vacant(v) = map.entry(ident.name) {
 +                    v.insert(cx.typeck_results().pat_ty(pat));
 +                }
 +                if let Some(ref as_pat) = *as_pat {
 +                    bindings_impl(cx, as_pat, map);
 +                }
 +            },
 +            PatKind::Or(fields) | PatKind::Tuple(fields, _) => {
 +                for pat in fields {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Struct(_, fields, _) => {
 +                for pat in fields {
 +                    bindings_impl(cx, &pat.pat, map);
 +                }
 +            },
 +            PatKind::Slice(lhs, ref mid, rhs) => {
 +                for pat in lhs {
 +                    bindings_impl(cx, pat, map);
 +                }
 +                if let Some(ref mid) = *mid {
 +                    bindings_impl(cx, mid, map);
 +                }
 +                for pat in rhs {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (),
 +        }
 +    }
 +
 +    let mut result = FxHashMap::default();
 +    bindings_impl(cx, pat, &mut result);
 +    result
 +}
 +
 +fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
 +where
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    for win in exprs.windows(2) {
 +        if eq(&win[0], &win[1]) {
 +            return Some((&win[0], &win[1]));
 +        }
 +    }
 +    None
 +}
 +
 +fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a T)>
 +where
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
 +        Some((&exprs[0], &exprs[1]))
 +    } else {
 +        None
 +    }
 +}
 +
 +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,
 +{
 +    if let Some(expr) = search_common_cases(&exprs, &eq) {
 +        return vec![expr];
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: FxHashMap<_, Vec<&_>> =
 +        FxHashMap::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
 +}
index 6ce36fd2360e1e9569cb748e566a3b38ce57ef4a,0000000000000000000000000000000000000000..9555459e240e9f874ba29132cb32eb47fe531161
mode 100644,000000..100644
--- /dev/null
@@@ -1,516 -1,0 +1,579 @@@
- use rustc_ast::ast::{AttrKind, Attribute};
 +use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
 +use if_chain::if_chain;
 +use itertools::Itertools;
- use rustc_span::source_map::{BytePos, MultiSpan, Span};
- use rustc_span::Pos;
++use rustc_ast::ast::{Async, AttrKind, Attribute, FnRetTy, ItemKind};
 +use rustc_ast::token::CommentKind;
 +use rustc_data_structures::fx::FxHashSet;
++use rustc_data_structures::sync::Lrc;
++use rustc_errors::emitter::EmitterWriter;
++use rustc_errors::Handler;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
++use rustc_parse::maybe_new_parser_from_source_str;
++use rustc_session::parse::ParseSess;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
- static LEAVE_MAIN_PATTERNS: &[&str] = &["static", "fn main() {}", "extern crate", "async fn main() {"];
++use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
++use rustc_span::{FileName, Pos};
++use std::io;
 +use std::ops::Range;
 +use url::Url;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for the presence of `_`, `::` or camel-case words
 +    /// outside ticks in documentation.
 +    ///
 +    /// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and
 +    /// camel-case probably indicates some code which should be included between
 +    /// ticks. `_` can also be used for emphasis in markdown, this lint tries to
 +    /// consider that.
 +    ///
 +    /// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks
 +    /// for is limited, and there are still false positives.
 +    ///
 +    /// **Examples:**
 +    /// ```rust
 +    /// /// Do something with the foo_bar parameter. See also
 +    /// /// that::other::module::foo.
 +    /// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
 +    /// fn doit(foo_bar: usize) {}
 +    /// ```
 +    pub DOC_MARKDOWN,
 +    pedantic,
 +    "presence of `_`, `::` or camel-case outside backticks in documentation"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for the doc comments of publicly visible
 +    /// unsafe functions and warns if there is no `# Safety` section.
 +    ///
 +    /// **Why is this bad?** Unsafe functions should document their safety
 +    /// preconditions, so that users can be sure they are using them safely.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// This function should really be documented
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    ///
 +    /// At least write a line about safety:
 +    ///
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// # Safety
 +    /// ///
 +    /// /// This function should not be called before the horsemen are ready.
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_SAFETY_DOC,
 +    style,
 +    "`pub unsafe fn` without `# Safety` docs"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks the doc comments of publicly visible functions that
 +    /// return a `Result` type and warns if there is no `# Errors` section.
 +    ///
 +    /// **Why is this bad?** Documenting the type of errors that can be returned from a
 +    /// function can help callers write code to handle the errors appropriately.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    ///
 +    /// Since the following function returns a `Result` it has an `# Errors` section in
 +    /// its doc comment:
 +    ///
 +    /// ```rust
 +    ///# use std::io;
 +    /// /// # Errors
 +    /// ///
 +    /// /// Will return `Err` if `filename` does not exist or the user does not have
 +    /// /// permission to read it.
 +    /// pub fn read(filename: String) -> io::Result<String> {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_ERRORS_DOC,
 +    pedantic,
 +    "`pub fn` returns `Result` without `# Errors` in doc comment"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `fn main() { .. }` in doctests
 +    ///
 +    /// **Why is this bad?** The test can be shorter (and likely more readable)
 +    /// if the `fn main()` is left implicit.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    /// ``````rust
 +    /// /// An example of a doctest with a `main()` function
 +    /// ///
 +    /// /// # Examples
 +    /// ///
 +    /// /// ```
 +    /// /// fn main() {
 +    /// ///     // this needs not be in an `fn`
 +    /// /// }
 +    /// /// ```
 +    /// fn needless_main() {
 +    ///     unimplemented!();
 +    /// }
 +    /// ``````
 +    pub NEEDLESS_DOCTEST_MAIN,
 +    style,
 +    "presence of `fn main() {` in code examples"
 +}
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Clone)]
 +pub struct DocMarkdown {
 +    valid_idents: FxHashSet<String>,
 +    in_trait_impl: bool,
 +}
 +
 +impl DocMarkdown {
 +    pub fn new(valid_idents: FxHashSet<String>) -> Self {
 +        Self {
 +            valid_idents,
 +            in_trait_impl: false,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, NEEDLESS_DOCTEST_MAIN]);
 +
 +impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
 +    fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
 +        check_attrs(cx, &self.valid_idents, &krate.item.attrs);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        match item.kind {
 +            hir::ItemKind::Fn(ref sig, _, body_id) => {
 +                if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id())
 +                    || in_external_macro(cx.tcx.sess, item.span))
 +                {
 +                    lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
 +                }
 +            },
 +            hir::ItemKind::Impl {
 +                of_trait: ref trait_ref,
 +                ..
 +            } => {
 +                self.in_trait_impl = trait_ref.is_some();
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        if let hir::ItemKind::Impl { .. } = item.kind {
 +            self.in_trait_impl = false;
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
 +            if !in_external_macro(cx.tcx.sess, item.span) {
 +                lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None);
 +            }
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +        if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
 +            lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
 +        }
 +    }
 +}
 +
 +fn lint_for_missing_headers<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    hir_id: hir::HirId,
 +    span: impl Into<MultiSpan> + Copy,
 +    sig: &hir::FnSig<'_>,
 +    headers: DocHeaders,
 +    body_id: Option<hir::BodyId>,
 +) {
 +    if !cx.access_levels.is_exported(hir_id) {
 +        return; // Private functions do not require doc comments
 +    }
 +    if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
 +        span_lint(
 +            cx,
 +            MISSING_SAFETY_DOC,
 +            span,
 +            "unsafe function's docs miss `# Safety` section",
 +        );
 +    }
 +    if !headers.errors {
 +        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
 +            span_lint(
 +                cx,
 +                MISSING_ERRORS_DOC,
 +                span,
 +                "docs for function returning `Result` missing `# Errors` section",
 +            );
 +        } else {
 +            if_chain! {
 +                if let Some(body_id) = body_id;
 +                if let Some(future) = cx.tcx.lang_items().future_trait();
 +                let def_id = cx.tcx.hir().body_owner_def_id(body_id);
 +                let mir = cx.tcx.optimized_mir(def_id.to_def_id());
 +                let ret_ty = mir.return_ty();
 +                if implements_trait(cx, ret_ty, future, &[]);
 +                if let ty::Opaque(_, subs) = ret_ty.kind;
 +                if let Some(gen) = subs.types().next();
 +                if let ty::Generator(_, subs, _) = gen.kind;
 +                if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type));
 +                then {
 +                    span_lint(
 +                        cx,
 +                        MISSING_ERRORS_DOC,
 +                        span,
 +                        "docs for function returning `Result` missing `# Errors` section",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Cleanup documentation decoration.
 +///
 +/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
 +/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
 +/// need to keep track of
 +/// the spans but this function is inspired from the later.
 +#[allow(clippy::cast_possible_truncation)]
 +#[must_use]
 +pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
 +    // one-line comments lose their prefix
 +    if comment_kind == CommentKind::Line {
 +        let mut doc = doc.to_owned();
 +        doc.push('\n');
 +        let len = doc.len();
 +        // +3 skips the opening delimiter
 +        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
 +    }
 +
 +    let mut sizes = vec![];
 +    let mut contains_initial_stars = false;
 +    for line in doc.lines() {
 +        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
 +        debug_assert_eq!(offset as u32 as usize, offset);
 +        contains_initial_stars |= line.trim_start().starts_with('*');
 +        // +1 adds the newline, +3 skips the opening delimiter
 +        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
 +    }
 +    if !contains_initial_stars {
 +        return (doc.to_string(), sizes);
 +    }
 +    // remove the initial '*'s if any
 +    let mut no_stars = String::with_capacity(doc.len());
 +    for line in doc.lines() {
 +        let mut chars = line.chars();
 +        while let Some(c) = chars.next() {
 +            if c.is_whitespace() {
 +                no_stars.push(c);
 +            } else {
 +                no_stars.push(if c == '*' { ' ' } else { c });
 +                break;
 +            }
 +        }
 +        no_stars.push_str(chars.as_str());
 +        no_stars.push('\n');
 +    }
 +
 +    (no_stars, sizes)
 +}
 +
 +#[derive(Copy, Clone)]
 +struct DocHeaders {
 +    safety: bool,
 +    errors: bool,
 +}
 +
 +fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
 +    let mut doc = String::new();
 +    let mut spans = vec![];
 +
 +    for attr in attrs {
 +        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
 +            let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
 +            spans.extend_from_slice(&current_spans);
 +            doc.push_str(&comment);
 +        } else if attr.has_name(sym!(doc)) {
 +            // ignore mix of sugared and non-sugared doc
 +            // don't trigger the safety or errors check
 +            return DocHeaders {
 +                safety: true,
 +                errors: true,
 +            };
 +        }
 +    }
 +
 +    let mut current = 0;
 +    for &mut (ref mut offset, _) in &mut spans {
 +        let offset_copy = *offset;
 +        *offset = current;
 +        current += offset_copy;
 +    }
 +
 +    if doc.is_empty() {
 +        return DocHeaders {
 +            safety: false,
 +            errors: false,
 +        };
 +    }
 +
 +    let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
 +    // Iterate over all `Events` and combine consecutive events into one
 +    let events = parser.coalesce(|previous, current| {
 +        use pulldown_cmark::Event::Text;
 +
 +        let previous_range = previous.1;
 +        let current_range = current.1;
 +
 +        match (previous.0, current.0) {
 +            (Text(previous), Text(current)) => {
 +                let mut previous = previous.to_string();
 +                previous.push_str(&current);
 +                Ok((Text(previous.into()), previous_range))
 +            },
 +            (previous, current) => Err(((previous, previous_range), (current, current_range))),
 +        }
 +    });
 +    check_doc(cx, valid_idents, events, &spans)
 +}
 +
 +const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail", "edition2018"];
 +
 +fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
 +    cx: &LateContext<'_>,
 +    valid_idents: &FxHashSet<String>,
 +    events: Events,
 +    spans: &[(usize, Span)],
 +) -> DocHeaders {
 +    // true if a safety header was found
 +    use pulldown_cmark::CodeBlockKind;
 +    use pulldown_cmark::Event::{
 +        Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 +    };
 +    use pulldown_cmark::Tag::{CodeBlock, Heading, Link};
 +
 +    let mut headers = DocHeaders {
 +        safety: false,
 +        errors: false,
 +    };
 +    let mut in_code = false;
 +    let mut in_link = None;
 +    let mut in_heading = false;
 +    let mut is_rust = false;
 +    for (event, range) in events {
 +        match event {
 +            Start(CodeBlock(ref kind)) => {
 +                in_code = true;
 +                if let CodeBlockKind::Fenced(lang) = kind {
 +                    is_rust =
 +                        lang.is_empty() || !lang.contains("ignore") && lang.split(',').any(|i| RUST_CODE.contains(&i));
 +                }
 +            },
 +            End(CodeBlock(_)) => {
 +                in_code = false;
 +                is_rust = false;
 +            },
 +            Start(Link(_, url, _)) => in_link = Some(url),
 +            End(Link(..)) => in_link = None,
 +            Start(Heading(_)) => in_heading = true,
 +            End(Heading(_)) => in_heading = false,
 +            Start(_tag) | End(_tag) => (), // We don't care about other tags
 +            Html(_html) => (),             // HTML is weird, just ignore it
 +            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
 +            FootnoteReference(text) | Text(text) => {
 +                if Some(&text) == in_link.as_ref() {
 +                    // Probably a link of the form `<http://example.com>`
 +                    // Which are represented as a link to "http://example.com" with
 +                    // text "http://example.com" by pulldown-cmark
 +                    continue;
 +                }
 +                headers.safety |= in_heading && text.trim() == "Safety";
 +                headers.errors |= in_heading && text.trim() == "Errors";
 +                let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) {
 +                    Ok(o) => o,
 +                    Err(e) => e - 1,
 +                };
 +                let (begin, span) = spans[index];
 +                if in_code {
 +                    if is_rust {
 +                        check_code(cx, &text, span);
 +                    }
 +                } else {
 +                    // Adjust for the beginning of the current `Event`
 +                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
 +
 +                    check_text(cx, valid_idents, &text, span);
 +                }
 +            },
 +        }
 +    }
 +    headers
 +}
 +
-     if text.contains("fn main() {") && !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) {
 +fn check_code(cx: &LateContext<'_>, text: &str, span: Span) {
++    fn has_needless_main(code: &str) -> bool {
++        let filename = FileName::anon_source_code(code);
++
++        let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
++        let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
++        let handler = Handler::with_emitter(false, None, box emitter);
++        let sess = ParseSess::with_span_handler(handler, sm);
++
++        let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) {
++            Ok(p) => p,
++            Err(errs) => {
++                for mut err in errs {
++                    err.cancel();
++                }
++                return false;
++            },
++        };
++
++        let mut relevant_main_found = false;
++        loop {
++            match parser.parse_item() {
++                Ok(Some(item)) => match &item.kind {
++                    // Tests with one of these items are ignored
++                    ItemKind::Static(..)
++                    | ItemKind::Const(..)
++                    | ItemKind::ExternCrate(..)
++                    | ItemKind::ForeignMod(..) => return false,
++                    // We found a main function ...
++                    ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => {
++                        let is_async = matches!(sig.header.asyncness, Async::Yes{..});
++                        let returns_nothing = match &sig.decl.output {
++                            FnRetTy::Default(..) => true,
++                            FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
++                            _ => false,
++                        };
++
++                        if returns_nothing && !is_async && !block.stmts.is_empty() {
++                            // This main function should be linted, but only if there are no other functions
++                            relevant_main_found = true;
++                        } else {
++                            // This main function should not be linted, we're done
++                            return false;
++                        }
++                    },
++                    // Another function was found; this case is ignored too
++                    ItemKind::Fn(..) => return false,
++                    _ => {},
++                },
++                Ok(None) => break,
++                Err(mut e) => {
++                    e.cancel();
++                    return false;
++                },
++            }
++        }
++
++        relevant_main_found
++    }
++
++    if has_needless_main(text) {
 +        span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
 +    }
 +}
 +
 +fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
 +    for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
 +        // Trim punctuation as in `some comment (see foo::bar).`
 +        //                                                   ^^
 +        // Or even as in `_foo bar_` which is emphasized.
 +        let word = word.trim_matches(|c: char| !c.is_alphanumeric());
 +
 +        if valid_idents.contains(word) {
 +            continue;
 +        }
 +
 +        // Adjust for the current word
 +        let offset = word.as_ptr() as usize - text.as_ptr() as usize;
 +        let span = Span::new(
 +            span.lo() + BytePos::from_usize(offset),
 +            span.lo() + BytePos::from_usize(offset + word.len()),
 +            span.ctxt(),
 +        );
 +
 +        check_word(cx, word, span);
 +    }
 +}
 +
 +fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
 +    /// Checks if a string is camel-case, i.e., contains at least two uppercase
 +    /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
 +    /// Plurals are also excluded (`IDs` is ok).
 +    fn is_camel_case(s: &str) -> bool {
 +        if s.starts_with(|c: char| c.is_digit(10)) {
 +            return false;
 +        }
 +
 +        let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
 +
 +        s.chars().all(char::is_alphanumeric)
 +            && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
 +            && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
 +    }
 +
 +    fn has_underscore(s: &str) -> bool {
 +        s != "_" && !s.contains("\\_") && s.contains('_')
 +    }
 +
 +    fn has_hyphen(s: &str) -> bool {
 +        s != "-" && s.contains('-')
 +    }
 +
 +    if let Ok(url) = Url::parse(word) {
 +        // try to get around the fact that `foo::bar` parses as a valid URL
 +        if !url.cannot_be_a_base() {
 +            span_lint(
 +                cx,
 +                DOC_MARKDOWN,
 +                span,
 +                "you should put bare URLs between `<`/`>` or make a proper Markdown link",
 +            );
 +
 +            return;
 +        }
 +    }
 +
 +    // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
 +    if has_underscore(word) && has_hyphen(word) {
 +        return;
 +    }
 +
 +    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
 +        span_lint(
 +            cx,
 +            DOC_MARKDOWN,
 +            span,
 +            &format!("you should put `{}` between ticks in the documentation", word),
 +        );
 +    }
 +}
index bae7c4647d487a898c944adbaa0d62aa2c124dd3,0000000000000000000000000000000000000000..19f56195ec1b483d693c8e20d6464ca4864c0fa9
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,94 @@@
- use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
 +//! Lint on unnecessary double comparisons. Some examples:
 +
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
-         let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
-         if !(spanless_eq.eq_expr(&llhs, &rlhs) && spanless_eq.eq_expr(&lrhs, &rrhs)) {
++use crate::utils::{eq_expr_value, snippet_with_applicability, span_lint_and_sugg};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for double comparisons that could be simplified to a single expression.
 +    ///
 +    ///
 +    /// **Why is this bad?** Readability.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 2;
 +    /// if x == y || x < y {}
 +    /// ```
 +    ///
 +    /// Could be written as:
 +    ///
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 2;
 +    /// if x <= y {}
 +    /// ```
 +    pub DOUBLE_COMPARISONS,
 +    complexity,
 +    "unnecessary double comparisons that can be simplified"
 +}
 +
 +declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
 +
 +impl<'tcx> DoubleComparisons {
 +    #[allow(clippy::similar_names)]
 +    fn check_binop(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) {
 +        let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) {
 +            (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
 +                (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
 +            },
 +            _ => return,
 +        };
++        if !(eq_expr_value(cx, &llhs, &rlhs) && eq_expr_value(cx, &lrhs, &rrhs)) {
 +            return;
 +        }
 +        macro_rules! lint_double_comparison {
 +            ($op:tt) => {{
 +                let mut applicability = Applicability::MachineApplicable;
 +                let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability);
 +                let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability);
 +                let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
 +                span_lint_and_sugg(
 +                    cx,
 +                    DOUBLE_COMPARISONS,
 +                    span,
 +                    "this binary expression can be simplified",
 +                    "try",
 +                    sugg,
 +                    applicability,
 +                );
 +            }};
 +        }
 +        #[rustfmt::skip]
 +        match (op, lkind, rkind) {
 +            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
 +                lint_double_comparison!(<=)
 +            },
 +            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
 +                lint_double_comparison!(>=)
 +            },
 +            (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
 +                lint_double_comparison!(!=)
 +            },
 +            (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
 +                lint_double_comparison!(==)
 +            },
 +            _ => (),
 +        };
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for DoubleComparisons {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.kind {
 +            Self::check_binop(cx, kind.node, lhs, rhs, expr.span);
 +        }
 +    }
 +}
index 1dfb2eaa579728d98bf628f9e3b467f9ca6725c5,0000000000000000000000000000000000000000..8ece44878fe32c6c7bcd1777e717cd6e185137ec
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,71 @@@
-                     &format!("Calling `{}()` is more concise than this calculation", suggested_fn),
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +
 +use crate::consts::{constant, Constant};
 +use crate::utils::paths;
 +use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
 +    /// from other `Duration` methods.
 +    ///
 +    /// **Why is this bad?** It's more concise to call `Duration::subsec_micros()` or
 +    /// `Duration::subsec_millis()` than to calculate them.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::time::Duration;
 +    /// let dur = Duration::new(5, 0);
 +    ///
 +    /// // Bad
 +    /// let _micros = dur.subsec_nanos() / 1_000;
 +    /// let _millis = dur.subsec_nanos() / 1_000_000;
 +    ///
 +    /// // Good
 +    /// let _micros = dur.subsec_micros();
 +    /// let _millis = dur.subsec_millis();
 +    /// ```
 +    pub DURATION_SUBSEC,
 +    complexity,
 +    "checks for calculation of subsecond microseconds or milliseconds"
 +}
 +
 +declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]);
 +
 +impl<'tcx> LateLintPass<'tcx> for DurationSubsec {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
 +            if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
 +            if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION);
 +            if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
 +            then {
 +                let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
 +                    ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
 +                    ("subsec_nanos", 1_000) => "subsec_micros",
 +                    _ => return,
 +                };
 +                let mut applicability = Applicability::MachineApplicable;
 +                span_lint_and_sugg(
 +                    cx,
 +                    DURATION_SUBSEC,
 +                    expr.span,
++                    &format!("calling `{}()` is more concise than this calculation", suggested_fn),
 +                    "try",
 +                    format!(
 +                        "{}.{}()",
 +                        snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
 +                        suggested_fn
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +}
index 91214f277be695cd6fbf83eb65d18b704509069b,0000000000000000000000000000000000000000..48caf48dbdb2cab0e80f0e2f4ee70e631c225a62
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,82 @@@
-                             "Clike enum variant discriminant is not portable to 32-bit targets",
 +//! lint on C-like enums that are `repr(isize/usize)` and have values that
 +//! don't fit into an `i32`
 +
 +use crate::consts::{miri_to_const, Constant};
 +use crate::utils::span_lint;
 +use rustc_ast::ast::{IntTy, UintTy};
 +use rustc_hir::{Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_middle::ty::util::IntTypeExt;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use std::convert::TryFrom;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for C-like enumerations that are
 +    /// `repr(isize/usize)` and have values that don't fit into an `i32`.
 +    ///
 +    /// **Why is this bad?** This will truncate the variant value on 32 bit
 +    /// architectures, but works fine on 64 bit.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # #[cfg(target_pointer_width = "64")]
 +    /// #[repr(usize)]
 +    /// enum NonPortable {
 +    ///     X = 0x1_0000_0000,
 +    ///     Y = 0,
 +    /// }
 +    /// ```
 +    pub ENUM_CLIKE_UNPORTABLE_VARIANT,
 +    correctness,
 +    "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
 +}
 +
 +declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
 +    #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss)]
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if cx.tcx.data_layout.pointer_size.bits() != 64 {
 +            return;
 +        }
 +        if let ItemKind::Enum(def, _) = &item.kind {
 +            for var in def.variants {
 +                if let Some(anon_const) = &var.disr_expr {
 +                    let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
 +                    let mut ty = cx.tcx.type_of(def_id.to_def_id());
 +                    let constant = cx
 +                        .tcx
 +                        .const_eval_poly(def_id.to_def_id())
 +                        .ok()
 +                        .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
 +                    if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
 +                        if let ty::Adt(adt, _) = ty.kind {
 +                            if adt.is_enum() {
 +                                ty = adt.repr.discr_type().to_ty(cx.tcx);
 +                            }
 +                        }
 +                        match ty.kind {
 +                            ty::Int(IntTy::Isize) => {
 +                                let val = ((val as i128) << 64) >> 64;
 +                                if i32::try_from(val).is_ok() {
 +                                    continue;
 +                                }
 +                            },
 +                            ty::Uint(UintTy::Usize) if val > u128::from(u32::MAX) => {},
 +                            _ => continue,
 +                        }
 +                        span_lint(
 +                            cx,
 +                            ENUM_CLIKE_UNPORTABLE_VARIANT,
 +                            var.span,
++                            "C-like enum variant discriminant is not portable to 32-bit targets",
 +                        );
 +                    };
 +                }
 +            }
 +        }
 +    }
 +}
index cb0fd59a2d4079acd2835fb752cd3e045cb43b1f,0000000000000000000000000000000000000000..a9294a87f15d060d23878f0ff1a15705713d8395
mode 100644,000000..100644
--- /dev/null
@@@ -1,327 -1,0 +1,327 @@@
-             span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
 +//! lint on enum variants that are prefixed or suffixed by the same characters
 +
 +use crate::utils::{camel_case, is_present_in_source};
 +use crate::utils::{span_lint, span_lint_and_help};
 +use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
 +use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForestCake,
 +    ///     HummingbirdCake,
 +    ///     BattenbergCake,
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForest,
 +    ///     Hummingbird,
 +    ///     Battenberg,
 +    /// }
 +    /// ```
 +    pub ENUM_VARIANT_NAMES,
 +    style,
 +    "enums where all variants share a prefix/postfix"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Detects public enumeration variants that are
 +    /// prefixed or suffixed by the same characters.
 +    ///
 +    /// **Why is this bad?** Public enumeration variant names should specify their variant,
 +    /// not repeat the enumeration name.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// pub enum Cake {
 +    ///     BlackForestCake,
 +    ///     HummingbirdCake,
 +    ///     BattenbergCake,
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// pub enum Cake {
 +    ///     BlackForest,
 +    ///     Hummingbird,
 +    ///     Battenberg,
 +    /// }
 +    /// ```
 +    pub PUB_ENUM_VARIANT_NAMES,
 +    pedantic,
 +    "public 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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForestCake;
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForest;
 +    /// }
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// // lib.rs
 +    /// mod foo;
 +    /// // foo.rs
 +    /// mod foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    pub MODULE_INCEPTION,
 +    style,
 +    "modules that have the same name as their parent module"
 +}
 +
 +pub struct EnumVariantNames {
 +    modules: Vec<(Symbol, String)>,
 +    threshold: u64,
 +}
 +
 +impl EnumVariantNames {
 +    #[must_use]
 +    pub fn new(threshold: u64) -> Self {
 +        Self {
 +            modules: Vec::new(),
 +            threshold,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(EnumVariantNames => [
 +    ENUM_VARIANT_NAMES,
 +    PUB_ENUM_VARIANT_NAMES,
 +    MODULE_NAME_REPETITIONS,
 +    MODULE_INCEPTION
 +]);
 +
 +/// Returns the number of chars that match from the start
 +#[must_use]
 +fn partial_match(pre: &str, name: &str) -> usize {
 +    let mut name_iter = name.chars();
 +    let _ = name_iter.next_back(); // make sure the name is never fully matched
 +    pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
 +}
 +
 +/// Returns the number of chars that match from the end
 +#[must_use]
 +fn partial_rmatch(post: &str, name: &str) -> usize {
 +    let mut name_iter = name.chars();
 +    let _ = name_iter.next(); // make sure the name is never fully matched
 +    post.chars()
 +        .rev()
 +        .zip(name_iter.rev())
 +        .take_while(|&(l, r)| l == r)
 +        .count()
 +}
 +
 +fn check_variant(
 +    cx: &EarlyContext<'_>,
 +    threshold: u64,
 +    def: &EnumDef,
 +    item_name: &str,
 +    item_name_chars: usize,
 +    span: Span,
 +    lint: &'static Lint,
 +) {
 +    if (def.variants.len() as u64) < threshold {
 +        return;
 +    }
 +    for var in &def.variants {
 +        let name = var.ident.name.as_str();
 +        if partial_match(item_name, &name) == 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, lint, var.span, "Variant name ends with the enum's name");
++            span_lint(cx, lint, var.span, "variant name starts with the enum's name");
 +        }
 +        if partial_rmatch(item_name, &name) == item_name_chars {
-         &format!("All variants have the same {}fix: `{}`", what, value),
++            span_lint(cx, lint, var.span, "variant name ends with the enum's name");
 +        }
 +    }
 +    let first = &def.variants[0].ident.name.as_str();
 +    let mut pre = &first[..camel_case::until(&*first)];
 +    let mut post = &first[camel_case::from(&*first)..];
 +    for var in &def.variants {
 +        let name = var.ident.name.as_str();
 +
 +        let pre_match = partial_match(pre, &name);
 +        pre = &pre[..pre_match];
 +        let pre_camel = camel_case::until(pre);
 +        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 = camel_case::until(&pre[..last]);
 +                pre = &pre[..last_camel];
 +            } else {
 +                break;
 +            }
 +        }
 +
 +        let post_match = partial_rmatch(post, &name);
 +        let post_end = post.len() - post_match;
 +        post = &post[post_end..];
 +        let post_camel = camel_case::from(post);
 +        post = &post[post_camel..];
 +    }
 +    let (what, value) = match (pre.is_empty(), post.is_empty()) {
 +        (true, true) => return,
 +        (false, _) => ("pre", pre),
 +        (true, false) => ("post", post),
 +    };
 +    span_lint_and_help(
 +        cx,
 +        lint,
 +        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 EarlyLintPass for EnumVariantNames {
 +    fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
 +        let last = self.modules.pop();
 +        assert!(last.is_some());
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 +        let item_name = item.ident.name.as_str();
 +        let item_name_chars = item_name.chars().count();
 +        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",
 +                            );
 +                        }
 +                    }
 +                    if item.vis.node.is_pub() {
 +                        let matching = partial_match(mod_camel, &item_camel);
 +                        let rmatching = partial_rmatch(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 == 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 == 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 {
 +            let lint = match item.vis.node {
 +                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
 +                _ => ENUM_VARIANT_NAMES,
 +            };
 +            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
 +        }
 +        self.modules.push((item.ident.name, item_camel));
 +    }
 +}
index 140cd21c34e67916b9922565cbaf11ec46a9adef,0000000000000000000000000000000000000000..e16ec783fab79c6c6744bcfaa958786ca7e912e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,233 -1,0 +1,233 @@@
-     implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq,
 +use crate::utils::{
-             if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
++    eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then,
 +};
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for equal operands to comparison, logical and
 +    /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
 +    /// `||`, `&`, `|`, `^`, `-` and `/`).
 +    ///
 +    /// **Why is this bad?** This is usually just a typo or a copy and paste error.
 +    ///
 +    /// **Known problems:** False negatives: We had some false positives regarding
 +    /// calls (notably [racer](https://github.com/phildawes/racer) had one instance
 +    /// of `x.pop() && x.pop()`), so we removed matching any function or method
 +    /// calls. We may introduce a list of known pure functions in the future.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = 1;
 +    /// if x + 1 == x + 1 {}
 +    /// ```
 +    pub EQ_OP,
 +    correctness,
 +    "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for arguments to `==` which have their address
 +    /// taken to satisfy a bound
 +    /// and suggests to dereference the other argument instead
 +    ///
 +    /// **Why is this bad?** It is more idiomatic to dereference the other argument.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// // Bad
 +    /// &x == y
 +    ///
 +    /// // Good
 +    /// x == *y
 +    /// ```
 +    pub OP_REF,
 +    style,
 +    "taking a reference to satisfy the type constraints on `==`"
 +}
 +
 +declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
 +
 +impl<'tcx> LateLintPass<'tcx> for EqOp {
 +    #[allow(clippy::similar_names, clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(op, ref left, ref right) = e.kind {
 +            if e.span.from_expansion() {
 +                return;
 +            }
 +            let macro_with_not_op = |expr_kind: &ExprKind<'_>| {
 +                if let ExprKind::Unary(_, ref expr) = *expr_kind {
 +                    in_macro(expr.span)
 +                } else {
 +                    false
 +                }
 +            };
 +            if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) {
 +                return;
 +            }
++            if is_valid_operator(op) && eq_expr_value(cx, left, right) {
 +                span_lint(
 +                    cx,
 +                    EQ_OP,
 +                    e.span,
 +                    &format!("equal expressions as operands to `{}`", op.node.as_str()),
 +                );
 +                return;
 +            }
 +            let (trait_id, requires_ref) = match op.node {
 +                BinOpKind::Add => (cx.tcx.lang_items().add_trait(), false),
 +                BinOpKind::Sub => (cx.tcx.lang_items().sub_trait(), false),
 +                BinOpKind::Mul => (cx.tcx.lang_items().mul_trait(), false),
 +                BinOpKind::Div => (cx.tcx.lang_items().div_trait(), false),
 +                BinOpKind::Rem => (cx.tcx.lang_items().rem_trait(), false),
 +                // don't lint short circuiting ops
 +                BinOpKind::And | BinOpKind::Or => return,
 +                BinOpKind::BitXor => (cx.tcx.lang_items().bitxor_trait(), false),
 +                BinOpKind::BitAnd => (cx.tcx.lang_items().bitand_trait(), false),
 +                BinOpKind::BitOr => (cx.tcx.lang_items().bitor_trait(), false),
 +                BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false),
 +                BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false),
 +                BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true),
 +                BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => {
 +                    (cx.tcx.lang_items().partial_ord_trait(), true)
 +                },
 +            };
 +            if let Some(trait_id) = trait_id {
 +                #[allow(clippy::match_same_arms)]
 +                match (&left.kind, &right.kind) {
 +                    // do not suggest to dereference literals
 +                    (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
 +                    // &foo == &bar
 +                    (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
 +                        let lty = cx.typeck_results().expr_ty(l);
 +                        let rty = cx.typeck_results().expr_ty(r);
 +                        let lcpy = is_copy(cx, lty);
 +                        let rcpy = is_copy(cx, rty);
 +                        // either operator autorefs or both args are copyable
 +                        if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) {
 +                            span_lint_and_then(
 +                                cx,
 +                                OP_REF,
 +                                e.span,
 +                                "needlessly taken reference of both operands",
 +                                |diag| {
 +                                    let lsnip = snippet(cx, l.span, "...").to_string();
 +                                    let rsnip = snippet(cx, r.span, "...").to_string();
 +                                    multispan_sugg(
 +                                        diag,
 +                                        "use the values directly",
 +                                        vec![(left.span, lsnip), (right.span, rsnip)],
 +                                    );
 +                                },
 +                            )
 +                        } else if lcpy
 +                            && !rcpy
 +                            && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
 +                        {
 +                            span_lint_and_then(
 +                                cx,
 +                                OP_REF,
 +                                e.span,
 +                                "needlessly taken reference of left operand",
 +                                |diag| {
 +                                    let lsnip = snippet(cx, l.span, "...").to_string();
 +                                    diag.span_suggestion(
 +                                        left.span,
 +                                        "use the left value directly",
 +                                        lsnip,
 +                                        Applicability::MaybeIncorrect, // FIXME #2597
 +                                    );
 +                                },
 +                            )
 +                        } else if !lcpy
 +                            && rcpy
 +                            && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
 +                        {
 +                            span_lint_and_then(
 +                                cx,
 +                                OP_REF,
 +                                e.span,
 +                                "needlessly taken reference of right operand",
 +                                |diag| {
 +                                    let rsnip = snippet(cx, r.span, "...").to_string();
 +                                    diag.span_suggestion(
 +                                        right.span,
 +                                        "use the right value directly",
 +                                        rsnip,
 +                                        Applicability::MaybeIncorrect, // FIXME #2597
 +                                    );
 +                                },
 +                            )
 +                        }
 +                    },
 +                    // &foo == bar
 +                    (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => {
 +                        let lty = cx.typeck_results().expr_ty(l);
 +                        let lcpy = is_copy(cx, lty);
 +                        if (requires_ref || lcpy)
 +                            && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
 +                        {
 +                            span_lint_and_then(
 +                                cx,
 +                                OP_REF,
 +                                e.span,
 +                                "needlessly taken reference of left operand",
 +                                |diag| {
 +                                    let lsnip = snippet(cx, l.span, "...").to_string();
 +                                    diag.span_suggestion(
 +                                        left.span,
 +                                        "use the left value directly",
 +                                        lsnip,
 +                                        Applicability::MaybeIncorrect, // FIXME #2597
 +                                    );
 +                                },
 +                            )
 +                        }
 +                    },
 +                    // foo == &bar
 +                    (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
 +                        let rty = cx.typeck_results().expr_ty(r);
 +                        let rcpy = is_copy(cx, rty);
 +                        if (requires_ref || rcpy)
 +                            && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
 +                        {
 +                            span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| {
 +                                let rsnip = snippet(cx, r.span, "...").to_string();
 +                                diag.span_suggestion(
 +                                    right.span,
 +                                    "use the right value directly",
 +                                    rsnip,
 +                                    Applicability::MaybeIncorrect, // FIXME #2597
 +                                );
 +                            })
 +                        }
 +                    },
 +                    _ => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn is_valid_operator(op: BinOp) -> bool {
 +    matches!(
 +        op.node,
 +        BinOpKind::Sub
 +            | BinOpKind::Div
 +            | BinOpKind::Eq
 +            | BinOpKind::Lt
 +            | BinOpKind::Le
 +            | BinOpKind::Gt
 +            | BinOpKind::Ge
 +            | BinOpKind::Ne
 +            | BinOpKind::And
 +            | BinOpKind::Or
 +            | BinOpKind::BitXor
 +            | BinOpKind::BitAnd
 +            | BinOpKind::BitOr
 +    )
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9ac5a45eb4590c6b65c9e8f29ee74647ebc2a896
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,110 @@@
++use crate::utils::{match_qpath, paths, span_lint_and_then, sugg};
++use if_chain::if_chain;
++use rustc_ast::util::parser::AssocOp;
++use rustc_errors::Applicability;
++use rustc_hir::{BinOpKind, Expr, ExprKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::ty;
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::source_map::Spanned;
++
++declare_clippy_lint! {
++    /// **What it does:** Checks for statements of the form `(a - b) < f32::EPSILON` or
++     /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
++     ///
++     /// **Why is this bad?** The code without `.abs()` is more likely to have a bug.
++     ///
++     /// **Known problems:** If the user can ensure that b is larger than a, the `.abs()` is
++     /// technically unneccessary. However, it will make the code more robust and doesn't have any
++     /// large performance implications. If the abs call was deliberately left out for performance
++     /// reasons, it is probably better to state this explicitly in the code, which then can be done
++     /// with an allow.
++     ///
++     /// **Example:**
++     ///
++     /// ```rust
++     /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
++     ///     (a - b) < f32::EPSILON
++     /// }
++     /// ```
++     /// Use instead:
++     /// ```rust
++     /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
++     ///     (a - b).abs() < f32::EPSILON
++     /// }
++     /// ```
++    pub FLOAT_EQUALITY_WITHOUT_ABS,
++    correctness,
++    "float equality check without `.abs()`"
++}
++
++declare_lint_pass!(FloatEqualityWithoutAbs => [FLOAT_EQUALITY_WITHOUT_ABS]);
++
++impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs {
++    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
++        let lhs;
++        let rhs;
++
++        // check if expr is a binary expression with a lt or gt operator
++        if let ExprKind::Binary(op, ref left, ref right) = expr.kind {
++            match op.node {
++                BinOpKind::Lt => {
++                    lhs = left;
++                    rhs = right;
++                },
++                BinOpKind::Gt => {
++                    lhs = right;
++                    rhs = left;
++                },
++                _ => return,
++            };
++        } else {
++            return;
++        }
++
++        if_chain! {
++
++            // left hand side is a substraction
++            if let ExprKind::Binary(
++                Spanned {
++                    node: BinOpKind::Sub,
++                    ..
++                },
++                val_l,
++                val_r,
++            ) = lhs.kind;
++
++            // right hand side matches either f32::EPSILON or f64::EPSILON
++            if let ExprKind::Path(ref epsilon_path) = rhs.kind;
++            if match_qpath(epsilon_path, &paths::F32_EPSILON) || match_qpath(epsilon_path, &paths::F64_EPSILON);
++
++            // values of the substractions on the left hand side are of the type float
++            let t_val_l = cx.typeck_results().expr_ty(val_l);
++            let t_val_r = cx.typeck_results().expr_ty(val_r);
++            if let ty::Float(_) = t_val_l.kind;
++            if let ty::Float(_) = t_val_r.kind;
++
++            then {
++                let sug_l = sugg::Sugg::hir(cx, &val_l, "..");
++                let sug_r = sugg::Sugg::hir(cx, &val_r, "..");
++                // format the suggestion
++                let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par());
++                // spans the lint
++                span_lint_and_then(
++                    cx,
++                    FLOAT_EQUALITY_WITHOUT_ABS,
++                    expr.span,
++                    "float equality check without `.abs()`",
++                    | diag | {
++                        diag.span_suggestion(
++                            lhs.span,
++                            "add `.abs()`",
++                            suggestion,
++                            Applicability::MaybeIncorrect,
++                        );
++                    }
++                );
++            }
++        }
++    }
++}
index 93f6ec92ec71328512aeb92b4b6b5976139fc45b,0000000000000000000000000000000000000000..1b02cee126d03b71af78ed69cba56e3cddbd9905
mode 100644,000000..100644
--- /dev/null
@@@ -1,725 -1,0 +1,721 @@@
- use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
 +use crate::consts::{
 +    constant, constant_simple, Constant,
 +    Constant::{Int, F32, F64},
 +};
-             if are_exprs_equal(cx, lmul_lhs, lmul_rhs);
-             if are_exprs_equal(cx, rmul_lhs, rmul_rhs);
++use crate::utils::{eq_expr_value, get_parent_expr, higher, numeric_literal, span_lint_and_sugg, 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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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();
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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();
 +    /// ```
 +    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::UnNeg, 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, ..
 +                    },
 +                    ref lhs,
 +                    ref 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,
 +                        "square can be computed more efficiently",
 +                        "consider using",
 +                        format!(
 +                            "{}.mul_add({}, {})",
 +                            Sugg::hir(cx, &args[0], ".."),
 +                            Sugg::hir(cx, &args[0], ".."),
 +                            Sugg::hir(cx, &other_addend, ".."),
 +                        ),
 +                        Applicability::MachineApplicable,
 +                    );
 +
 +                    return;
 +                }
 +            }
 +
 +            span_lint_and_sugg(
 +                cx,
 +                SUBOPTIMAL_FLOPS,
 +                expr.span,
 +                "square can be computed more efficiently",
 +                "consider using",
 +                format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
 +    if let ExprKind::Binary(
 +        Spanned {
 +            node: BinOpKind::Add, ..
 +        },
 +        ref add_lhs,
 +        ref 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, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
 +            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
-             BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && are_exprs_equal(cx, left, test),
-             BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && are_exprs_equal(cx, right, test),
++            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, &lmul_lhs, ".."), 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, .. },
 +                ref _lspan,
 +                ref largs,
 +                _
 +            ) = add_lhs.kind;
 +            if let ExprKind::MethodCall(
 +                PathSegment { ident: rmethod_name, .. },
 +                ref _rspan,
 +                ref rargs,
 +                _
 +            ) = 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 {
 +                return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), 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, .. }, ref lhs, ref 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(ref path, _, ref method_args, _) = lhs.kind;
 +        if cx.typeck_results().expr_ty(&method_args[0]).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, &method_args[0], "..")
 +                ),
 +                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, .. }, ref lhs, ref 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, left) && are_exprs_equal(cx, right, test),
-             BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && are_exprs_equal(cx, left, test),
++            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 {
- fn are_exprs_equal(cx: &LateContext<'_>, expr1: &Expr<'_>, expr2: &Expr<'_>) -> bool {
-     SpanlessEq::new(cx).ignore_fn().eq_expr(expr1, expr2)
- }
++            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
 +    }
 +}
 +
-         if are_exprs_equal(cx, expr1_negated, expr2) {
 +/// 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::UnNeg, expr1_negated) = &expr1.kind {
-         if are_exprs_equal(cx, expr1, expr2_negated) {
++        if eq_expr_value(cx, expr1_negated, expr2) {
 +            return Some((false, expr2));
 +        }
 +    }
 +    if let ExprKind::Unary(UnOp::UnNeg, expr2_negated) = &expr2.kind {
-                     method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1])
++        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((cond, body, Some(else_body))) = higher::if_block(&expr);
 +        if let ExprKind::Block(block, _) = body.kind;
 +        if block.stmts.is_empty();
 +        if let Some(if_body_expr) = block.expr;
 +        if let ExprKind::Block(else_block, _) = else_body.kind;
 +        if else_block.stmts.is_empty();
 +        if let Some(else_body_expr) = else_block.expr;
 +        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, .. }, _, ref args_a, _) = expr_a.kind;
 +        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref 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(_, _, ref largs, _) = lhs.kind;
 +        if let ExprKind::MethodCall(_, _, ref rargs, _) = 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[0], ".."), Sugg::hir(cx, &rargs[0], ".."),),
 +                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)
 +            {
 +                span_lint_and_sugg(
 +                    cx,
 +                    SUBOPTIMAL_FLOPS,
 +                    expr.span,
 +                    "conversion to degrees can be done more accurately",
 +                    "consider using",
 +                    format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")),
 +                    Applicability::MachineApplicable,
 +                );
 +            } else if
 +                (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
 +                (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
 +            {
 +                span_lint_and_sugg(
 +                    cx,
 +                    SUBOPTIMAL_FLOPS,
 +                    expr.span,
 +                    "conversion to radians can be done more accurately",
 +                    "consider using",
 +                    format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::MethodCall(ref 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 5b22df5fe491e70e3afcadb2933e176a6492ff47,0000000000000000000000000000000000000000..28b20cdeac343ecdf30c3cf66be49aa909765b96
mode 100644,000000..100644
--- /dev/null
@@@ -1,72 -1,0 +1,72 @@@
-                     "Matching on `Some` with `ok()` is redundant",
-                     &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
 +use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:*** Checks for unnecessary `ok()` in if let.
 +    ///
 +    /// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match
 +    /// on `Ok(pat)`
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// for i in iter {
 +    ///     if let Some(value) = i.parse().ok() {
 +    ///         vec.push(value)
 +    ///     }
 +    /// }
 +    /// ```
 +    /// Could be written:
 +    ///
 +    /// ```ignore
 +    /// for i in iter {
 +    ///     if let Ok(value) = i.parse() {
 +    ///         vec.push(value)
 +    ///     }
 +    /// }
 +    /// ```
 +    pub IF_LET_SOME_RESULT,
 +    style,
 +    "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
 +}
 +
 +declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for OkIfLet {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! { //begin checking variables
 +            if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match
 +            if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let
 +            if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
 +            if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pat.kind; //get operation
 +            if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
 +            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym!(result_type));
 +            if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
 +                let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability);
 +                let sugg = format!(
 +                    "if let Ok({}) = {}",
 +                    some_expr_string,
 +                    trimmed_ok.trim().trim_end_matches('.'),
 +                );
 +                span_lint_and_sugg(
 +                    cx,
 +                    IF_LET_SOME_RESULT,
 +                    expr.span.with_hi(op.span.hi()),
++                    "matching on `Some` with `ok()` is redundant",
++                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
 +                    sugg,
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +}
index c11e291f98e4b41766dbf22c8940d8f9fff3b74c,0000000000000000000000000000000000000000..b86d2e766566bd16391dde7b738d288d873050ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,83 -1,0 +1,83 @@@
-                             "Unnecessary boolean `not` operation",
 +//! lint on if branches that could be swapped so no `!` operation is necessary
 +//! on the condition
 +
 +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +use crate::utils::span_lint_and_help;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
 +    /// else branch.
 +    ///
 +    /// **Why is this bad?** Negations reduce the readability of statements.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let v: Vec<usize> = vec![];
 +    /// # fn a() {}
 +    /// # fn b() {}
 +    /// if !v.is_empty() {
 +    ///     a()
 +    /// } else {
 +    ///     b()
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// # let v: Vec<usize> = vec![];
 +    /// # fn a() {}
 +    /// # fn b() {}
 +    /// if v.is_empty() {
 +    ///     b()
 +    /// } else {
 +    ///     a()
 +    /// }
 +    /// ```
 +    pub IF_NOT_ELSE,
 +    pedantic,
 +    "`if` branches that could be swapped so no negation operation is necessary on the condition"
 +}
 +
 +declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 +
 +impl EarlyLintPass for IfNotElse {
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
 +        if in_external_macro(cx.sess(), item.span) {
 +            return;
 +        }
 +        if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
 +            if let ExprKind::Block(..) = els.kind {
 +                match cond.kind {
 +                    ExprKind::Unary(UnOp::Not, _) => {
 +                        span_lint_and_help(
 +                            cx,
 +                            IF_NOT_ELSE,
 +                            item.span,
-                             "Unnecessary `!=` operation",
++                            "unnecessary boolean `not` operation",
 +                            None,
 +                            "remove the `!` and swap the blocks of the `if`/`else`",
 +                        );
 +                    },
 +                    ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
 +                        span_lint_and_help(
 +                            cx,
 +                            IF_NOT_ELSE,
 +                            item.span,
++                            "unnecessary `!=` operation",
 +                            None,
 +                            "change to `==` and swap the blocks of the `if`/`else`",
 +                        );
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        }
 +    }
 +}
index 5f931a0addedf6b3781460b545d15a7ec46dc629,0000000000000000000000000000000000000000..b57fe8dc4269e341b7f6299cae07331aff409562
mode 100644,000000..100644
--- /dev/null
@@@ -1,166 -1,0 +1,166 @@@
-         "Implicitly performing saturating subtraction",
 +use crate::utils::{higher, in_macro, match_qpath, span_lint_and_sugg, SpanlessEq};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, StmtKind};
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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 in_macro(expr.span) {
 +            return;
 +        }
 +        if_chain! {
 +            if let Some((ref cond, ref then, None)) = higher::if_block(&expr);
 +
 +            // Check if the conditional expression is a binary operation
 +            if let ExprKind::Binary(ref cond_op, ref cond_left, ref 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 the true condition block has only one statement
 +            if let ExprKind::Block(ref block, _) = then.kind;
 +            if block.stmts.len() == 1 && block.expr.is_none();
 +
 +            // Check if assign operation is done
 +            if let StmtKind::Semi(ref e) = block.stmts[0].kind;
 +            if let Some(target) = subtracts_one(cx, e);
 +
 +            // Extracting out the variable name
 +            if let ExprKind::Path(ref assign_path) = target.kind;
 +            if let QPath::Resolved(_, ref ares_path) = assign_path;
 +
 +            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: [&str; 5] = ["i8", "i16", "i32", "i64", "i128"];
 +
 +                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);
 +                            };
 +                        }
 +                    },
 +                    ExprKind::Path(ref cond_num_path) => {
 +                        if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "MIN"])) {
 +                            print_lint_and_sugg(cx, &var_name, expr);
 +                        };
 +                    },
 +                    ExprKind::Call(ref func, _) => {
 +                        if let ExprKind::Path(ref cond_num_path) = func.kind {
 +                            if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) {
 +                                print_lint_and_sugg(cx, &var_name, expr);
 +                            }
 +                        };
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> {
 +    match expr.kind {
 +        ExprKind::AssignOp(ref op1, ref target, ref 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(ref target, ref value, _) => {
 +            if_chain! {
 +                if let ExprKind::Binary(ref op1, ref left1, ref 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,
-         format!("{} = {}.saturating_sub({});", var_name, var_name, 1.to_string()),
++        "implicitly performing saturating subtraction",
 +        "try",
++        format!("{} = {}.saturating_sub({});", var_name, var_name, '1'),
 +        Applicability::MachineApplicable,
 +    );
 +}
index 9fb10c7f62768583ec311d0748f68796cf0a5b32,0000000000000000000000000000000000000000..4e6bb604785417977320c72d6de98ad623abd59e
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,94 @@@
-                             "Multiple implementations of this structure",
 +//! lint on inherent implementations
 +
 +use crate::utils::{in_macro, span_lint_and_then};
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir::{def_id, Crate, Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for multiple inherent implementations of a struct
 +    ///
 +    /// **Why is this bad?** Splitting the implementation of a type makes the code harder to navigate.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn one() {}
 +    /// }
 +    /// impl X {
 +    ///     fn other() {}
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn one() {}
 +    ///     fn other() {}
 +    /// }
 +    /// ```
 +    pub MULTIPLE_INHERENT_IMPL,
 +    restriction,
 +    "Multiple inherent impl that could be grouped"
 +}
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Default)]
 +pub struct MultipleInherentImpl {
 +    impls: FxHashMap<def_id::DefId, Span>,
 +}
 +
 +impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
 +    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Impl {
 +            ref generics,
 +            of_trait: None,
 +            ..
 +        } = item.kind
 +        {
 +            // Remember for each inherent implementation encountered its span and generics
 +            // but filter out implementations that have generic params (type or lifetime)
 +            // or are derived from a macro
 +            if !in_macro(item.span) && generics.params.is_empty() {
 +                self.impls.insert(item.hir_id.owner.to_def_id(), item.span);
 +            }
 +        }
 +    }
 +
 +    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'_>) {
 +        if let Some(item) = krate.items.values().next() {
 +            // Retrieve all inherent implementations from the crate, grouped by type
 +            for impls in cx
 +                .tcx
 +                .crate_inherent_impls(item.hir_id.owner.to_def_id().krate)
 +                .inherent_impls
 +                .values()
 +            {
 +                // Filter out implementations that have generic params (type or lifetime)
 +                let mut impl_spans = impls.iter().filter_map(|impl_def| self.impls.get(impl_def));
 +                if let Some(initial_span) = impl_spans.next() {
 +                    impl_spans.for_each(|additional_span| {
 +                        span_lint_and_then(
 +                            cx,
 +                            MULTIPLE_INHERENT_IMPL,
 +                            *additional_span,
-                                 diag.span_note(*initial_span, "First implementation here");
++                            "multiple implementations of this structure",
 +                            |diag| {
++                                diag.span_note(*initial_span, "first implementation here");
 +                            },
 +                        )
 +                    })
 +                }
 +            }
 +        }
 +    }
 +}
index e91fb0c2f27cd0340caf1ace6afb0fb8e70d7098,0000000000000000000000000000000000000000..c629ee05ab97c1e2740441170c3ad142c857fbb7
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,171 @@@
-             "Unnecessary `>= y + 1` or `x - 1 >=`",
 +//! lint on blocks unnecessarily using >= with a + 1 or - 1
 +
 +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +use crate::utils::{snippet_opt, span_lint_and_sugg};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
 +    ///
 +    /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 1;
 +    /// if x >= y + 1 {}
 +    /// ```
 +    ///
 +    /// Could be written as:
 +    ///
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 1;
 +    /// if x > y {}
 +    /// ```
 +    pub INT_PLUS_ONE,
 +    complexity,
 +    "instead of using `x >= y + 1`, use `x > y`"
 +}
 +
 +declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]);
 +
 +// cases:
 +// BinOpKind::Ge
 +// x >= y + 1
 +// x - 1 >= y
 +//
 +// BinOpKind::Le
 +// x + 1 <= y
 +// x <= y - 1
 +
 +#[derive(Copy, Clone)]
 +enum Side {
 +    LHS,
 +    RHS,
 +}
 +
 +impl IntPlusOne {
 +    #[allow(clippy::cast_sign_loss)]
 +    fn check_lit(lit: &Lit, target_value: i128) -> bool {
 +        if let LitKind::Int(value, ..) = lit.kind {
 +            return value == (target_value as u128);
 +        }
 +        false
 +    }
 +
 +    fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
 +        match (binop, &lhs.kind, &rhs.kind) {
 +            // case where `x - 1 >= ...` or `-1 + x >= ...`
 +            (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
 +                match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
 +                    // `-1 + x`
 +                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
 +                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
 +                    },
 +                    // `x - 1`
 +                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
 +                    },
 +                    _ => None,
 +                }
 +            },
 +            // case where `... >= y + 1` or `... >= 1 + y`
 +            (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
 +                if rhskind.node == BinOpKind::Add =>
 +            {
 +                match (&rhslhs.kind, &rhsrhs.kind) {
 +                    // `y + 1` and `1 + y`
 +                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
 +                    },
 +                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
 +                    },
 +                    _ => None,
 +                }
 +            }
 +            // case where `x + 1 <= ...` or `1 + x <= ...`
 +            (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
 +                if lhskind.node == BinOpKind::Add =>
 +            {
 +                match (&lhslhs.kind, &lhsrhs.kind) {
 +                    // `1 + x` and `x + 1`
 +                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
 +                    },
 +                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
 +                    },
 +                    _ => None,
 +                }
 +            }
 +            // case where `... >= y - 1` or `... >= -1 + y`
 +            (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
 +                match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
 +                    // `-1 + y`
 +                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
 +                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
 +                    },
 +                    // `y - 1`
 +                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
 +                    },
 +                    _ => None,
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    fn generate_recommendation(
 +        cx: &EarlyContext<'_>,
 +        binop: BinOpKind,
 +        node: &Expr,
 +        other_side: &Expr,
 +        side: Side,
 +    ) -> Option<String> {
 +        let binop_string = match binop {
 +            BinOpKind::Ge => ">",
 +            BinOpKind::Le => "<",
 +            _ => return None,
 +        };
 +        if let Some(snippet) = snippet_opt(cx, node.span) {
 +            if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
 +                let rec = match side {
 +                    Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
 +                    Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
 +                };
 +                return rec;
 +            }
 +        }
 +        None
 +    }
 +
 +    fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
 +        span_lint_and_sugg(
 +            cx,
 +            INT_PLUS_ONE,
 +            block.span,
-             if let Some(ref rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
-                 Self::emit_warning(cx, item, rec.clone());
++            "unnecessary `>= y + 1` or `x - 1 >=`",
 +            "change it to",
 +            recommendation,
 +            Applicability::MachineApplicable, // snippet
 +        );
 +    }
 +}
 +
 +impl EarlyLintPass for IntPlusOne {
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
 +        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind {
++            if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
++                Self::emit_warning(cx, item, rec);
 +            }
 +        }
 +    }
 +}
index e5daa30f8ca15745759706c41534552cb355d8d8,0000000000000000000000000000000000000000..b691d363d2f2165ca03be278f0706a82f018e0bb
mode 100644,000000..100644
--- /dev/null
@@@ -1,316 -1,0 +1,301 @@@
- use crate::utils::{get_item_name, higher, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
++use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
 +use rustc_ast::ast::LitKind;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::{Span, Spanned, Symbol};
 +
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if x.len() == 0 {
 +    ///     ..
 +    /// }
 +    /// if y.len() != 0 {
 +    ///     ..
 +    /// }
 +    /// ```
 +    /// instead use
 +    /// ```ignore
 +    /// if x.is_empty() {
 +    ///     ..
 +    /// }
 +    /// if !y.is_empty() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// impl X {
 +    ///     pub fn len(&self) -> usize {
 +    ///         ..
 +    ///     }
 +    /// }
 +    /// ```
 +    pub LEN_WITHOUT_IS_EMPTY,
 +    style,
 +    "traits or impls with a public `len` method but no corresponding `is_empty` method"
 +}
 +
 +declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LenZero {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if item.span.from_expansion() {
 +            return;
 +        }
 +
 +        match item.kind {
 +            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
 +            ItemKind::Impl {
 +                of_trait: None,
 +                items: ref impl_items,
 +                ..
 +            } => check_impl_items(cx, item, impl_items),
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref 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: &str) -> bool {
 +        item.ident.name.as_str() == name
 +            && if let AssocItemKind::Fn { has_self } = item.kind {
 +                has_self && {
 +                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
 +                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
 +                }
 +            } else {
 +                false
 +            }
 +    }
 +
 +    // fill the set with current and super traits
 +    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, 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.hir_id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
 +        let mut current_and_super_traits = FxHashSet::default();
 +        let visited_trait_def_id = cx.tcx.hir().local_def_id(visited_trait.hir_id);
 +        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
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +fn check_impl_items(cx: &LateContext<'_>, item: &Item<'_>, impl_items: &[ImplItemRef<'_>]) {
 +    fn is_named_self(cx: &LateContext<'_>, item: &ImplItemRef<'_>, name: &str) -> bool {
 +        item.ident.name.as_str() == name
 +            && if let AssocItemKind::Fn { has_self } = item.kind {
 +                has_self && {
 +                    let did = cx.tcx.hir().local_def_id(item.id.hir_id);
 +                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
 +                }
 +            } else {
 +                false
 +            }
 +    }
 +
 +    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
 +        if cx.access_levels.is_exported(is_empty.id.hir_id) {
 +            return;
 +        } else {
 +            "a private"
 +        }
 +    } else {
 +        "no corresponding"
 +    };
 +
 +    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
 +        if cx.access_levels.is_exported(i.id.hir_id) {
 +            let def_id = cx.tcx.hir().local_def_id(item.hir_id);
 +            let ty = cx.tcx.type_of(def_id);
 +
 +            span_lint(
 +                cx,
 +                LEN_WITHOUT_IS_EMPTY,
 +                item.span,
 +                &format!(
 +                    "item `{}` has a public `len` method but {} `is_empty` method",
 +                    ty, is_empty
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
 +    if let (&ExprKind::MethodCall(ref method_path, _, ref 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)
 +    }
 +}
 +
 +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.as_str() == "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,
 +            );
 +        }
 +    }
 +}
 +
 +/// Checks if this type has an `is_empty` method.
 +fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-     /// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
-     fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-         higher::range(expr).map_or(false, |_| {
-             !cx.tcx
-                 .features()
-                 .declared_lib_features
-                 .iter()
-                 .any(|(name, _)| name.as_str() == "range_is_empty")
-         })
-     }
 +    /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
 +    fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
 +        if let ty::AssocKind::Fn = item.kind {
 +            if 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
 +            }
 +        } 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))
 +        })
 +    }
 +
-     if should_skip_range(cx, expr) {
-         return false;
-     }
 +    let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr));
 +    match ty.kind {
 +        ty::Dynamic(ref 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 aa1002636406ad29310267f2067c045e396689c4,0000000000000000000000000000000000000000..577ce6523b491f4342a4138f75c229fe61bcd9f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1853 -1,0 +1,1878 @@@
- mod let_and_return;
 +// error-pattern:cargo-clippy
 +
 +#![feature(bindings_after_at)]
 +#![feature(box_patterns)]
 +#![feature(box_syntax)]
 +#![feature(concat_idents)]
 +#![feature(crate_visibility_modifier)]
 +#![feature(drain_filter)]
 +#![feature(or_patterns)]
 +#![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
 +#![deny(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_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;
 +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;
 +
 +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`, `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.
 +///     ///
 +///     /// **Known problems:** None. (Or describe where it could go wrong.)
 +///     ///
 +///     /// **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, 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
 +        }
 +    };
 +}
 +
 +mod consts;
 +#[macro_use]
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod atomic_ordering;
 +mod attrs;
 +mod await_holding_lock;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod booleans;
 +mod bytecount;
 +mod cargo_common_metadata;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod dbg_macro;
 +mod default_trait_access;
 +mod dereference;
 +mod derive;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_bounds;
 +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 erasing_op;
 +mod escape;
 +mod eta_reduction;
 +mod eval_order_dependence;
 +mod excessive_bools;
 +mod exit;
 +mod explicit_write;
 +mod fallible_impl_from;
++mod float_equality_without_abs;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod formatting;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_let_some_result;
 +mod if_not_else;
 +mod implicit_return;
 +mod implicit_saturating_sub;
 +mod indexing_slicing;
 +mod infinite_iter;
 +mod inherent_impl;
 +mod inherent_to_string;
 +mod inline_fn_without_body;
 +mod int_plus_one;
 +mod integer_division;
 +mod items_after_statements;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_stack_arrays;
 +mod len_zero;
-         &let_and_return::LET_AND_RETURN,
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
 +mod manual_async_fn;
 +mod manual_non_exhaustive;
 +mod map_clone;
 +mod map_identity;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod matches;
 +mod mem_discriminant;
 +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_inline;
 +mod modulo_arithmetic;
 +mod multiple_crate_versions;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bool;
 +mod needless_borrow;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_pass_by_value;
 +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 open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_static_lifetimes;
 +mod reference;
 +mod regex;
 +mod repeat_once;
 +mod returns;
++mod self_assignment;
 +mod serde_api;
 +mod shadow;
 +mod single_component_path_imports;
 +mod slow_vector_initialization;
 +mod stable_sort_primitive;
 +mod strings;
 +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 trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod trivially_copy_pass_by_ref;
 +mod try_err;
 +mod types;
 +mod unicode;
 +mod unit_return_expecting_ord;
 +mod unnamed_address;
 +mod unnecessary_sort_by;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_io_amount;
 +mod unused_self;
++mod unused_unit;
 +mod unwrap;
++mod unwrap_in_result;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_dependencies;
 +mod wildcard_imports;
 +mod write;
 +mod zero_div_zero;
 +// end lints modules, do not remove this comment, it’s used in `update_lints`
 +
 +pub use crate::utils::conf::Conf;
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_pre_expansion_pass(|| box write::Write::default());
 +    store.register_pre_expansion_pass(|| box attrs::EarlyAttributes);
 +    store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro);
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(args: &[rustc_ast::NestedMetaItem], sess: &Session) -> Conf {
 +    use std::path::Path;
 +    match utils::conf::file_from_args(args) {
 +        Ok(file_name) => {
 +            // if the user specified a file, it must exist, otherwise default to `clippy.toml` but
 +            // do not require the file to exist
 +            let file_name = match file_name {
 +                Some(file_name) => file_name,
 +                None => 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 file_name = if file_name.is_relative() {
 +                sess.local_crate_source_file
 +                    .as_deref()
 +                    .and_then(Path::parent)
 +                    .unwrap_or_else(|| Path::new(""))
 +                    .join(file_name)
 +            } else {
 +                file_name
 +            };
 +
 +            let (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
 +        },
 +        Err((err, span)) => {
 +            sess.struct_span_err(span, err)
 +                .span_note(span, "Clippy will use default configuration")
 +                .emit();
 +            Conf::default()
 +        },
 +    }
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +#[rustfmt::skip]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
 +    // begin deprecated lints, do not remove this comment, it’s used in `update_lints`
 +    store.register_removed(
 +        "clippy::should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "clippy::extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "clippy::range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "clippy::unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "clippy::unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "clippy::str_to_string",
 +        "using `str::to_string` is common even today and specialization will likely happen soon",
 +    );
 +    store.register_removed(
 +        "clippy::string_to_string",
 +        "using `string::to_string` is common even today and specialization will likely happen soon",
 +    );
 +    store.register_removed(
 +        "clippy::misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "clippy::assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "clippy::if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "clippy::unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "clippy::invalid_ref",
 +        "superseded by rustc lint `invalid_value`",
 +    );
 +    store.register_removed(
 +        "clippy::unused_collect",
 +        "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
 +    );
 +    store.register_removed(
 +        "clippy::into_iter_on_array",
 +        "this lint has been uplifted to rustc and is now called `array_into_iter`",
 +    );
 +    store.register_removed(
 +        "clippy::unused_label",
 +        "this lint has been uplifted to rustc and is now called `unused_labels`",
 +    );
 +    store.register_removed(
 +        "clippy::replace_consts",
 +        "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants",
 +    );
 +    store.register_removed(
 +        "clippy::regex_macro",
 +        "the regex! macro has been removed from the regex crate in 2018",
 +    );
 +    // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 +
 +    // begin register lints, do not remove this comment, it’s used in `update_lints`
 +    store.register_lints(&[
 +        &approx_const::APPROX_CONSTANT,
 +        &arithmetic::FLOAT_ARITHMETIC,
 +        &arithmetic::INTEGER_ARITHMETIC,
 +        &as_conversions::AS_CONVERSIONS,
 +        &assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
 +        &assign_ops::ASSIGN_OP_PATTERN,
 +        &assign_ops::MISREFACTORED_ASSIGN_OP,
 +        &atomic_ordering::INVALID_ATOMIC_ORDERING,
 +        &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::UNKNOWN_CLIPPY_LINTS,
 +        &attrs::USELESS_ATTRIBUTE,
 +        &await_holding_lock::AWAIT_HOLDING_LOCK,
 +        &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,
 +        &booleans::LOGIC_BUG,
 +        &booleans::NONMINIMAL_BOOL,
 +        &bytecount::NAIVE_BYTECOUNT,
 +        &cargo_common_metadata::CARGO_COMMON_METADATA,
 +        &checked_conversions::CHECKED_CONVERSIONS,
 +        &cognitive_complexity::COGNITIVE_COMPLEXITY,
 +        &collapsible_if::COLLAPSIBLE_IF,
 +        &comparison_chain::COMPARISON_CHAIN,
 +        &copies::IFS_SAME_COND,
 +        &copies::IF_SAME_THEN_ELSE,
 +        &copies::MATCH_SAME_ARMS,
 +        &copies::SAME_FUNCTIONS_IN_IF_CONDITION,
 +        &copy_iterator::COPY_ITERATOR,
 +        &dbg_macro::DBG_MACRO,
 +        &default_trait_access::DEFAULT_TRAIT_ACCESS,
 +        &dereference::EXPLICIT_DEREF_METHODS,
 +        &derive::DERIVE_HASH_XOR_EQ,
 +        &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
 +        &derive::EXPL_IMPL_CLONE_ON_COPY,
 +        &derive::UNSAFE_DERIVE_DESERIALIZE,
 +        &doc::DOC_MARKDOWN,
 +        &doc::MISSING_ERRORS_DOC,
 +        &doc::MISSING_SAFETY_DOC,
 +        &doc::NEEDLESS_DOCTEST_MAIN,
 +        &double_comparison::DOUBLE_COMPARISONS,
 +        &double_parens::DOUBLE_PARENS,
 +        &drop_bounds::DROP_BOUNDS,
 +        &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,
 +        &enum_variants::PUB_ENUM_VARIANT_NAMES,
 +        &eq_op::EQ_OP,
 +        &eq_op::OP_REF,
 +        &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,
 +        &exit::EXIT,
 +        &explicit_write::EXPLICIT_WRITE,
 +        &fallible_impl_from::FALLIBLE_IMPL_FROM,
++        &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,
 +        &formatting::POSSIBLE_MISSING_COMMA,
 +        &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
 +        &formatting::SUSPICIOUS_ELSE_FORMATTING,
 +        &formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
 +        &functions::DOUBLE_MUST_USE,
 +        &functions::MUST_USE_CANDIDATE,
 +        &functions::MUST_USE_UNIT,
 +        &functions::NOT_UNSAFE_PTR_ARG_DEREF,
 +        &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_let_some_result::IF_LET_SOME_RESULT,
 +        &if_not_else::IF_NOT_ELSE,
 +        &implicit_return::IMPLICIT_RETURN,
 +        &implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
 +        &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,
 +        &inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
 +        &int_plus_one::INT_PLUS_ONE,
 +        &integer_division::INTEGER_DIVISION,
 +        &items_after_statements::ITEMS_AFTER_STATEMENTS,
 +        &large_const_arrays::LARGE_CONST_ARRAYS,
 +        &large_enum_variant::LARGE_ENUM_VARIANT,
 +        &large_stack_arrays::LARGE_STACK_ARRAYS,
 +        &len_zero::LEN_WITHOUT_IS_EMPTY,
 +        &len_zero::LEN_ZERO,
-         &returns::UNUSED_UNIT,
 +        &let_if_seq::USELESS_LET_IF_SEQ,
 +        &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,
 +        &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_MEMCPY,
 +        &loops::MUT_RANGE_BOUND,
 +        &loops::NEEDLESS_COLLECT,
 +        &loops::NEEDLESS_RANGE_LOOP,
 +        &loops::NEVER_LOOP,
 +        &loops::SAME_ITEM_PUSH,
 +        &loops::WHILE_IMMUTABLE_CONDITION,
 +        &loops::WHILE_LET_LOOP,
 +        &loops::WHILE_LET_ON_ITERATOR,
 +        &macro_use::MACRO_USE_IMPORTS,
 +        &main_recursion::MAIN_RECURSION,
 +        &manual_async_fn::MANUAL_ASYNC_FN,
 +        &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
 +        &map_clone::MAP_CLONE,
 +        &map_identity::MAP_IDENTITY,
 +        &map_unit_fn::OPTION_MAP_UNIT_FN,
 +        &map_unit_fn::RESULT_MAP_UNIT_FN,
 +        &match_on_vec_items::MATCH_ON_VEC_ITEMS,
 +        &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_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_discriminant::MEM_DISCRIMINANT_NON_ENUM,
 +        &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::CHARS_LAST_CMP,
 +        &methods::CHARS_NEXT_CMP,
 +        &methods::CLONE_DOUBLE_REF,
 +        &methods::CLONE_ON_COPY,
 +        &methods::CLONE_ON_REF_PTR,
 +        &methods::EXPECT_FUN_CALL,
 +        &methods::EXPECT_USED,
 +        &methods::FILETYPE_IS_FILE,
 +        &methods::FILTER_MAP,
 +        &methods::FILTER_MAP_NEXT,
 +        &methods::FILTER_NEXT,
 +        &methods::FIND_MAP,
 +        &methods::FLAT_MAP_IDENTITY,
 +        &methods::GET_UNWRAP,
 +        &methods::INEFFICIENT_TO_STRING,
 +        &methods::INTO_ITER_ON_REF,
 +        &methods::ITERATOR_STEP_BY_ZERO,
 +        &methods::ITER_CLONED_COLLECT,
 +        &methods::ITER_NEXT_SLICE,
 +        &methods::ITER_NTH,
 +        &methods::ITER_NTH_ZERO,
 +        &methods::ITER_SKIP_NEXT,
 +        &methods::MANUAL_SATURATING_ARITHMETIC,
 +        &methods::MAP_FLATTEN,
 +        &methods::MAP_UNWRAP_OR,
 +        &methods::NEW_RET_NO_SELF,
 +        &methods::OK_EXPECT,
 +        &methods::OPTION_AS_REF_DEREF,
 +        &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_PATTERN,
++        &methods::SINGLE_CHAR_PUSH_STR,
 +        &methods::SKIP_WHILE_NEXT,
 +        &methods::STRING_EXTEND_CHARS,
 +        &methods::SUSPICIOUS_MAP,
 +        &methods::TEMPORARY_CSTRING_AS_PTR,
 +        &methods::UNINIT_ASSUMED_INIT,
 +        &methods::UNNECESSARY_FILTER_MAP,
 +        &methods::UNNECESSARY_FOLD,
++        &methods::UNNECESSARY_LAZY_EVALUATIONS,
 +        &methods::UNWRAP_USED,
 +        &methods::USELESS_ASREF,
 +        &methods::WRONG_PUB_SELF_CONVENTION,
 +        &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::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_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
 +        &modulo_arithmetic::MODULO_ARITHMETIC,
 +        &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
 +        &mut_key::MUTABLE_KEY_TYPE,
 +        &mut_mut::MUT_MUT,
 +        &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_bool::BOOL_COMPARISON,
 +        &needless_bool::NEEDLESS_BOOL,
 +        &needless_borrow::NEEDLESS_BORROW,
 +        &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
 +        &needless_continue::NEEDLESS_CONTINUE,
 +        &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
 +        &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::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,
 +        &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_unimplemented::PANIC,
 +        &panic_unimplemented::PANIC_PARAMS,
 +        &panic_unimplemented::TODO,
 +        &panic_unimplemented::UNIMPLEMENTED,
 +        &panic_unimplemented::UNREACHABLE,
 +        &partialeq_ne_impl::PARTIALEQ_NE_IMPL,
 +        &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
 +        &pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
 +        &precedence::PRECEDENCE,
 +        &ptr::CMP_NULL,
 +        &ptr::MUT_FROM_REF,
 +        &ptr::PTR_ARG,
 +        &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
 +        &question_mark::QUESTION_MARK,
 +        &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_field_names::REDUNDANT_FIELD_NAMES,
 +        &redundant_pub_crate::REDUNDANT_PUB_CRATE,
 +        &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
 +        &reference::DEREF_ADDROF,
 +        &reference::REF_IN_DEREF,
 +        &regex::INVALID_REGEX,
 +        &regex::TRIVIAL_REGEX,
 +        &repeat_once::REPEAT_ONCE,
++        &returns::LET_AND_RETURN,
 +        &returns::NEEDLESS_RETURN,
-     store.register_late_pass(|| box vec::UselessVec);
++        &self_assignment::SELF_ASSIGNMENT,
 +        &serde_api::SERDE_API_MISUSE,
 +        &shadow::SHADOW_REUSE,
 +        &shadow::SHADOW_SAME,
 +        &shadow::SHADOW_UNRELATED,
 +        &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
 +        &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
 +        &stable_sort_primitive::STABLE_SORT_PRIMITIVE,
 +        &strings::STRING_ADD,
 +        &strings::STRING_ADD_ASSIGN,
 +        &strings::STRING_LIT_AS_BYTES,
 +        &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,
 +        &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_PTR_TO_PTR,
 +        &transmute::TRANSMUTE_PTR_TO_REF,
 +        &transmute::UNSOUND_COLLECTION_TRANSMUTE,
 +        &transmute::USELESS_TRANSMUTE,
 +        &transmute::WRONG_TRANSMUTE,
 +        &transmuting_null::TRANSMUTING_NULL,
 +        &trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF,
 +        &try_err::TRY_ERR,
 +        &types::ABSURD_EXTREME_COMPARISONS,
 +        &types::BORROWED_BOX,
 +        &types::BOX_VEC,
 +        &types::CAST_LOSSLESS,
 +        &types::CAST_POSSIBLE_TRUNCATION,
 +        &types::CAST_POSSIBLE_WRAP,
 +        &types::CAST_PRECISION_LOSS,
 +        &types::CAST_PTR_ALIGNMENT,
 +        &types::CAST_REF_TO_MUT,
 +        &types::CAST_SIGN_LOSS,
 +        &types::CHAR_LIT_AS_U8,
 +        &types::FN_TO_NUMERIC_CAST,
 +        &types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +        &types::IMPLICIT_HASHER,
 +        &types::INVALID_UPCAST_COMPARISONS,
 +        &types::LET_UNIT_VALUE,
 +        &types::LINKEDLIST,
 +        &types::OPTION_OPTION,
 +        &types::REDUNDANT_ALLOCATION,
 +        &types::TYPE_COMPLEXITY,
 +        &types::UNIT_ARG,
 +        &types::UNIT_CMP,
 +        &types::UNNECESSARY_CAST,
 +        &types::VEC_BOX,
 +        &unicode::NON_ASCII_LITERAL,
 +        &unicode::UNICODE_NOT_NFC,
 +        &unicode::ZERO_WIDTH_SPACE,
 +        &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
 +        &unnamed_address::FN_ADDRESS_COMPARISONS,
 +        &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
 +        &unnecessary_sort_by::UNNECESSARY_SORT_BY,
 +        &unnested_or_patterns::UNNESTED_OR_PATTERNS,
 +        &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
 +        &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,
 +        &use_self::USE_SELF,
 +        &useless_conversion::USELESS_CONVERSION,
 +        &utils::internal_lints::CLIPPY_LINTS_INTERNAL,
 +        &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
 +        &utils::internal_lints::COMPILER_LINT_FUNCTIONS,
 +        &utils::internal_lints::DEFAULT_LINT,
 +        &utils::internal_lints::LINT_WITHOUT_LINT_PASS,
 +        &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
 +        &utils::internal_lints::PRODUCE_ICE,
 +        &vec::USELESS_VEC,
 +        &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_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,
 +    ]);
 +    // end register lints, do not remove this comment, it’s used in `update_lints`
 +
 +    store.register_late_pass(|| box await_holding_lock::AwaitHoldingLock);
 +    store.register_late_pass(|| box serde_api::SerdeAPI);
 +    store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
 +    store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
 +    store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
 +    store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
 +    store.register_late_pass(|| box utils::author::Author);
 +    let vec_box_size_threshold = conf.vec_box_size_threshold;
 +    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
 +    store.register_late_pass(|| box booleans::NonminimalBool);
 +    store.register_late_pass(|| box eq_op::EqOp);
 +    store.register_late_pass(|| box enum_clike::UnportableVariant);
 +    store.register_late_pass(|| box float_literal::FloatLiteral);
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
 +    store.register_late_pass(|| box ptr::Ptr);
 +    store.register_late_pass(|| box needless_bool::NeedlessBool);
 +    store.register_late_pass(|| box needless_bool::BoolComparison);
 +    store.register_late_pass(|| box approx_const::ApproxConstant);
 +    store.register_late_pass(|| box misc::MiscLints);
 +    store.register_late_pass(|| box eta_reduction::EtaReduction);
 +    store.register_late_pass(|| box identity_op::IdentityOp);
 +    store.register_late_pass(|| box erasing_op::ErasingOp);
 +    store.register_late_pass(|| box mut_mut::MutMut);
 +    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
 +    store.register_late_pass(|| box len_zero::LenZero);
 +    store.register_late_pass(|| box attrs::Attributes);
 +    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
 +    store.register_late_pass(|| box unicode::Unicode);
 +    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
 +    store.register_late_pass(|| box strings::StringAdd);
 +    store.register_late_pass(|| box implicit_return::ImplicitReturn);
 +    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
 +    store.register_late_pass(|| box methods::Methods);
 +    store.register_late_pass(|| box map_clone::MapClone);
 +    store.register_late_pass(|| box shadow::Shadow);
 +    store.register_late_pass(|| box types::LetUnitValue);
 +    store.register_late_pass(|| box types::UnitCmp);
 +    store.register_late_pass(|| box loops::Loops);
 +    store.register_late_pass(|| box main_recursion::MainRecursion::default());
 +    store.register_late_pass(|| box lifetimes::Lifetimes);
 +    store.register_late_pass(|| box entry::HashMapPass);
 +    store.register_late_pass(|| box ranges::Ranges);
 +    store.register_late_pass(|| box types::Casts);
 +    let type_complexity_threshold = conf.type_complexity_threshold;
 +    store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
 +    store.register_late_pass(|| box matches::Matches::default());
 +    store.register_late_pass(|| box minmax::MinMaxPass);
 +    store.register_late_pass(|| box open_options::OpenOptions);
 +    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
 +    store.register_late_pass(|| box mutex_atomic::Mutex);
 +    store.register_late_pass(|| box needless_update::NeedlessUpdate);
 +    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
 +    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
 +    store.register_late_pass(|| box no_effect::NoEffect);
 +    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
 +    store.register_late_pass(|| box transmute::Transmute);
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
++    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
 +    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
 +    store.register_late_pass(|| box strings::StringLitAsBytes);
 +    store.register_late_pass(|| box derive::Derive);
 +    store.register_late_pass(|| box types::CharLitAsU8);
-     store.register_early_pass(|| box returns::Return);
-     store.register_late_pass(|| box let_and_return::LetReturn);
 +    store.register_late_pass(|| box drop_bounds::DropBounds);
 +    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
 +    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
 +    store.register_late_pass(|| box empty_enum::EmptyEnum);
 +    store.register_late_pass(|| box types::AbsurdExtremeComparisons);
 +    store.register_late_pass(|| box types::InvalidUpcastComparisons);
 +    store.register_late_pass(|| box regex::Regex::default());
 +    store.register_late_pass(|| box copies::CopyAndPaste);
 +    store.register_late_pass(|| box copy_iterator::CopyIterator);
 +    store.register_late_pass(|| box format::UselessFormat);
 +    store.register_late_pass(|| box swap::Swap);
 +    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
 +    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
 +    let too_many_arguments_threshold1 = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold2 = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold1, too_many_lines_threshold2));
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
 +    store.register_late_pass(|| box neg_multiply::NegMultiply);
 +    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
 +    store.register_late_pass(|| box mem_forget::MemForget);
 +    store.register_late_pass(|| box mem_replace::MemReplace);
 +    store.register_late_pass(|| box arithmetic::Arithmetic::default());
 +    store.register_late_pass(|| box assign_ops::AssignOps);
 +    store.register_late_pass(|| box let_if_seq::LetIfSeq);
 +    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
 +    store.register_late_pass(|| box missing_doc::MissingDoc::new());
 +    store.register_late_pass(|| box missing_inline::MissingInline);
 +    store.register_late_pass(|| box if_let_some_result::OkIfLet);
 +    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
 +    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
 +    store.register_late_pass(|| box explicit_write::ExplicitWrite);
 +    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
 +    let trivially_copy_pass_by_ref = trivially_copy_pass_by_ref::TriviallyCopyPassByRef::new(
 +        conf.trivial_copy_size_limit,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move || box trivially_copy_pass_by_ref);
 +    store.register_late_pass(|| box try_err::TryErr);
 +    store.register_late_pass(|| box use_self::UseSelf);
 +    store.register_late_pass(|| box bytecount::ByteCount);
 +    store.register_late_pass(|| box infinite_iter::InfiniteIter);
 +    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
 +    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
 +    store.register_late_pass(|| box types::ImplicitHasher);
 +    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
 +    store.register_late_pass(|| box types::UnitArg);
 +    store.register_late_pass(|| box double_comparison::DoubleComparisons);
 +    store.register_late_pass(|| box question_mark::QuestionMark);
 +    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
 +    store.register_late_pass(|| box map_unit_fn::MapUnit);
 +    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default());
 +    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
 +    store.register_late_pass(|| box unwrap::Unwrap);
 +    store.register_late_pass(|| box duration_subsec::DurationSubsec);
 +    store.register_late_pass(|| box default_trait_access::DefaultTraitAccess);
 +    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
 +    store.register_late_pass(|| box non_copy_const::NonCopyConst);
 +    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
 +    store.register_late_pass(|| box redundant_clone::RedundantClone);
 +    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
 +    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
 +    store.register_late_pass(|| box types::RefToMut);
 +    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
 +    store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
 +    store.register_late_pass(|| box transmuting_null::TransmutingNull);
 +    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
 +    store.register_late_pass(|| box checked_conversions::CheckedConversions);
 +    store.register_late_pass(|| box integer_division::IntegerDivision);
 +    store.register_late_pass(|| box inherent_to_string::InherentToString);
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
 +    store.register_late_pass(|| box comparison_chain::ComparisonChain);
 +    store.register_late_pass(|| box mut_key::MutableKeyType);
 +    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
 +    store.register_early_pass(|| box reference::DerefAddrOf);
 +    store.register_early_pass(|| box reference::RefInDeref);
 +    store.register_early_pass(|| box double_parens::DoubleParens);
++    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
 +    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
 +    store.register_early_pass(|| box if_not_else::IfNotElse);
 +    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
 +    store.register_early_pass(|| box int_plus_one::IntPlusOne);
 +    store.register_early_pass(|| box formatting::Formatting);
 +    store.register_early_pass(|| box misc_early::MiscEarlyLints);
 +    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
 +    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
-         LintId::of(&let_and_return::LET_AND_RETURN),
++    store.register_early_pass(|| box unused_unit::UnusedUnit);
++    store.register_late_pass(|| box returns::Return);
 +    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
 +    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
 +    store.register_early_pass(|| box precedence::Precedence);
 +    store.register_early_pass(|| box needless_continue::NeedlessContinue);
 +    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
 +    store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes);
 +    store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
 +    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
 +    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
 +    store.register_early_pass(|| box literal_representation::LiteralDigitGrouping);
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
 +    store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
 +    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
 +    store.register_late_pass(|| box unused_self::UnusedSelf);
 +    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
 +    store.register_late_pass(|| box exit::Exit);
 +    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
 +    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
 +    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
 +    store.register_early_pass(|| box as_conversions::AsConversions);
 +    store.register_early_pass(|| box utils::internal_lints::ProduceIce);
 +    store.register_late_pass(|| box let_underscore::LetUnderscore);
 +    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
 +    store.register_early_pass(|| box 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 excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
 +    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
 +    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
 +    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
 +    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
 +    store.register_late_pass(|| box dereference::Dereferencing);
 +    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
 +    store.register_late_pass(|| box future_not_send::FutureNotSend);
 +    store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
 +    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
 +    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
 +    store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
 +    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
 +    store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
 +    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
 +        single_char_binding_names_threshold,
 +    });
 +    store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
 +    store.register_late_pass(|| box macro_use::MacroUseImports::default());
 +    store.register_late_pass(|| box map_identity::MapIdentity);
 +    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
 +    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
 +    store.register_late_pass(|| box repeat_once::RepeatOnce);
++    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
++    store.register_late_pass(|| box self_assignment::SelfAssignment);
++    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
 +
 +    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +        LintId::of(&arithmetic::FLOAT_ARITHMETIC),
 +        LintId::of(&arithmetic::INTEGER_ARITHMETIC),
 +        LintId::of(&as_conversions::AS_CONVERSIONS),
 +        LintId::of(&dbg_macro::DBG_MACRO),
 +        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +        LintId::of(&exit::EXIT),
 +        LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
 +        LintId::of(&implicit_return::IMPLICIT_RETURN),
 +        LintId::of(&indexing_slicing::INDEXING_SLICING),
 +        LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL),
 +        LintId::of(&integer_division::INTEGER_DIVISION),
 +        LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE),
 +        LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION),
 +        LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
 +        LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
 +        LintId::of(&mem_forget::MEM_FORGET),
 +        LintId::of(&methods::CLONE_ON_REF_PTR),
 +        LintId::of(&methods::EXPECT_USED),
 +        LintId::of(&methods::FILETYPE_IS_FILE),
 +        LintId::of(&methods::GET_UNWRAP),
 +        LintId::of(&methods::UNWRAP_USED),
 +        LintId::of(&methods::WRONG_PUB_SELF_CONVENTION),
 +        LintId::of(&misc::FLOAT_CMP_CONST),
 +        LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN),
 +        LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
 +        LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
 +        LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC),
 +        LintId::of(&panic_unimplemented::PANIC),
 +        LintId::of(&panic_unimplemented::TODO),
 +        LintId::of(&panic_unimplemented::UNIMPLEMENTED),
 +        LintId::of(&panic_unimplemented::UNREACHABLE),
 +        LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
 +        LintId::of(&shadow::SHADOW_REUSE),
 +        LintId::of(&shadow::SHADOW_SAME),
 +        LintId::of(&strings::STRING_ADD),
++        LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
 +        LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
 +        LintId::of(&write::PRINT_STDOUT),
 +        LintId::of(&write::USE_DEBUG),
 +    ]);
 +
 +    store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
 +        LintId::of(&attrs::INLINE_ALWAYS),
 +        LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK),
 +        LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
 +        LintId::of(&copies::MATCH_SAME_ARMS),
 +        LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
 +        LintId::of(&copy_iterator::COPY_ITERATOR),
 +        LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS),
 +        LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
 +        LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
 +        LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
 +        LintId::of(&doc::DOC_MARKDOWN),
 +        LintId::of(&doc::MISSING_ERRORS_DOC),
 +        LintId::of(&empty_enum::EMPTY_ENUM),
 +        LintId::of(&enum_variants::MODULE_NAME_REPETITIONS),
 +        LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES),
 +        LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
 +        LintId::of(&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
 +        LintId::of(&excessive_bools::STRUCT_EXCESSIVE_BOOLS),
 +        LintId::of(&functions::MUST_USE_CANDIDATE),
 +        LintId::of(&functions::TOO_MANY_LINES),
 +        LintId::of(&if_not_else::IF_NOT_ELSE),
 +        LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
 +        LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
 +        LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
 +        LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
 +        LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
 +        LintId::of(&literal_representation::UNREADABLE_LITERAL),
 +        LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
 +        LintId::of(&loops::EXPLICIT_ITER_LOOP),
 +        LintId::of(&macro_use::MACRO_USE_IMPORTS),
 +        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
 +        LintId::of(&matches::MATCH_BOOL),
 +        LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
 +        LintId::of(&matches::MATCH_WILD_ERR_ARM),
 +        LintId::of(&matches::SINGLE_MATCH_ELSE),
 +        LintId::of(&methods::FILTER_MAP),
 +        LintId::of(&methods::FILTER_MAP_NEXT),
 +        LintId::of(&methods::FIND_MAP),
 +        LintId::of(&methods::INEFFICIENT_TO_STRING),
 +        LintId::of(&methods::MAP_FLATTEN),
 +        LintId::of(&methods::MAP_UNWRAP_OR),
 +        LintId::of(&misc::USED_UNDERSCORE_BINDING),
 +        LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX),
 +        LintId::of(&mut_mut::MUT_MUT),
 +        LintId::of(&needless_continue::NEEDLESS_CONTINUE),
 +        LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
 +        LintId::of(&non_expressive_names::SIMILAR_NAMES),
 +        LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
 +        LintId::of(&ranges::RANGE_MINUS_ONE),
 +        LintId::of(&ranges::RANGE_PLUS_ONE),
 +        LintId::of(&shadow::SHADOW_UNRELATED),
 +        LintId::of(&strings::STRING_ADD_ASSIGN),
 +        LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
 +        LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
 +        LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
 +        LintId::of(&types::CAST_LOSSLESS),
 +        LintId::of(&types::CAST_POSSIBLE_TRUNCATION),
 +        LintId::of(&types::CAST_POSSIBLE_WRAP),
 +        LintId::of(&types::CAST_PRECISION_LOSS),
 +        LintId::of(&types::CAST_PTR_ALIGNMENT),
 +        LintId::of(&types::CAST_SIGN_LOSS),
 +        LintId::of(&types::IMPLICIT_HASHER),
 +        LintId::of(&types::INVALID_UPCAST_COMPARISONS),
 +        LintId::of(&types::LET_UNIT_VALUE),
 +        LintId::of(&types::LINKEDLIST),
 +        LintId::of(&types::OPTION_OPTION),
 +        LintId::of(&unicode::NON_ASCII_LITERAL),
 +        LintId::of(&unicode::UNICODE_NOT_NFC),
 +        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
 +        LintId::of(&unused_self::UNUSED_SELF),
 +        LintId::of(&wildcard_imports::ENUM_GLOB_USE),
 +        LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
 +    ]);
 +
 +    store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
 +        LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL),
 +        LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
 +        LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
 +        LintId::of(&utils::internal_lints::DEFAULT_LINT),
 +        LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
 +        LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
 +        LintId::of(&utils::internal_lints::PRODUCE_ICE),
 +    ]);
 +
 +    store.register_group(true, "clippy::all", Some("clippy"), vec![
 +        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(&atomic_ordering::INVALID_ATOMIC_ORDERING),
 +        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::UNKNOWN_CLIPPY_LINTS),
 +        LintId::of(&attrs::USELESS_ATTRIBUTE),
 +        LintId::of(&bit_mask::BAD_BIT_MASK),
 +        LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
 +        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
 +        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
 +        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +        LintId::of(&booleans::LOGIC_BUG),
 +        LintId::of(&booleans::NONMINIMAL_BOOL),
 +        LintId::of(&bytecount::NAIVE_BYTECOUNT),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
 +        LintId::of(&comparison_chain::COMPARISON_CHAIN),
 +        LintId::of(&copies::IFS_SAME_COND),
 +        LintId::of(&copies::IF_SAME_THEN_ELSE),
 +        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_bounds::DROP_BOUNDS),
 +        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(&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(&functions::DOUBLE_MUST_USE),
 +        LintId::of(&functions::MUST_USE_UNIT),
 +        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +        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(&if_let_some_result::IF_LET_SOME_RESULT),
 +        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(&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::LEN_WITHOUT_IS_EMPTY),
 +        LintId::of(&len_zero::LEN_ZERO),
-         LintId::of(&returns::UNUSED_UNIT),
 +        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(&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_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::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_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +        LintId::of(&map_clone::MAP_CLONE),
 +        LintId::of(&map_identity::MAP_IDENTITY),
 +        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
 +        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
 +        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_discriminant::MEM_DISCRIMINANT_NON_ENUM),
 +        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::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::FILTER_NEXT),
 +        LintId::of(&methods::FLAT_MAP_IDENTITY),
 +        LintId::of(&methods::INTO_ITER_ON_REF),
 +        LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
 +        LintId::of(&methods::ITER_CLONED_COLLECT),
 +        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_SATURATING_ARITHMETIC),
 +        LintId::of(&methods::NEW_RET_NO_SELF),
 +        LintId::of(&methods::OK_EXPECT),
 +        LintId::of(&methods::OPTION_AS_REF_DEREF),
 +        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_PATTERN),
++        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
 +        LintId::of(&methods::SKIP_WHILE_NEXT),
 +        LintId::of(&methods::STRING_EXTEND_CHARS),
 +        LintId::of(&methods::SUSPICIOUS_MAP),
 +        LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR),
 +        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::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::FLOAT_CMP),
 +        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_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_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_expressive_names::MANY_SINGLE_CHAR_NAMES),
 +        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(&panic_unimplemented::PANIC_PARAMS),
 +        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +        LintId::of(&precedence::PRECEDENCE),
 +        LintId::of(&ptr::CMP_NULL),
 +        LintId::of(&ptr::MUT_FROM_REF),
 +        LintId::of(&ptr::PTR_ARG),
 +        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +        LintId::of(&question_mark::QUESTION_MARK),
 +        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_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +        LintId::of(&reference::DEREF_ADDROF),
 +        LintId::of(&reference::REF_IN_DEREF),
 +        LintId::of(&regex::INVALID_REGEX),
 +        LintId::of(&regex::TRIVIAL_REGEX),
 +        LintId::of(&repeat_once::REPEAT_ONCE),
++        LintId::of(&returns::LET_AND_RETURN),
 +        LintId::of(&returns::NEEDLESS_RETURN),
-         LintId::of(&let_and_return::LET_AND_RETURN),
++        LintId::of(&self_assignment::SELF_ASSIGNMENT),
 +        LintId::of(&serde_api::SERDE_API_MISUSE),
 +        LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +        LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
 +        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
 +        LintId::of(&strings::STRING_LIT_AS_BYTES),
 +        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_PTR_TO_PTR),
 +        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::ABSURD_EXTREME_COMPARISONS),
 +        LintId::of(&types::BORROWED_BOX),
 +        LintId::of(&types::BOX_VEC),
 +        LintId::of(&types::CAST_REF_TO_MUT),
 +        LintId::of(&types::CHAR_LIT_AS_U8),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +        LintId::of(&types::REDUNDANT_ALLOCATION),
 +        LintId::of(&types::TYPE_COMPLEXITY),
 +        LintId::of(&types::UNIT_ARG),
 +        LintId::of(&types::UNIT_CMP),
 +        LintId::of(&types::UNNECESSARY_CAST),
 +        LintId::of(&types::VEC_BOX),
 +        LintId::of(&unicode::ZERO_WIDTH_SPACE),
 +        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +        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(&useless_conversion::USELESS_CONVERSION),
 +        LintId::of(&vec::USELESS_VEC),
 +        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),
 +    ]);
 +
 +    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(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +        LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
 +        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
 +        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
 +        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
 +        LintId::of(&comparison_chain::COMPARISON_CHAIN),
 +        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(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +        LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
 +        LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +        LintId::of(&functions::DOUBLE_MUST_USE),
 +        LintId::of(&functions::MUST_USE_UNIT),
 +        LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
 +        LintId::of(&inherent_to_string::INHERENT_TO_STRING),
 +        LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
 +        LintId::of(&len_zero::LEN_ZERO),
-         LintId::of(&returns::UNUSED_UNIT),
 +        LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +        LintId::of(&loops::EMPTY_LOOP),
 +        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_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +        LintId::of(&map_clone::MAP_CLONE),
 +        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::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::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_PUSH_STR),
 +        LintId::of(&methods::STRING_EXTEND_CHARS),
 +        LintId::of(&methods::UNNECESSARY_FOLD),
++        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
 +        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_reference::UNNECESSARY_MUT_PASSED),
 +        LintId::of(&neg_multiply::NEG_MULTIPLY),
 +        LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
 +        LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +        LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
 +        LintId::of(&panic_unimplemented::PANIC_PARAMS),
 +        LintId::of(&ptr::CMP_NULL),
 +        LintId::of(&ptr::PTR_ARG),
 +        LintId::of(&question_mark::QUESTION_MARK),
 +        LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
 +        LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +        LintId::of(&regex::TRIVIAL_REGEX),
++        LintId::of(&returns::LET_AND_RETURN),
 +        LintId::of(&returns::NEEDLESS_RETURN),
 +        LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +        LintId::of(&strings::STRING_LIT_AS_BYTES),
 +        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(&types::FN_TO_NUMERIC_CAST),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +        LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
++        LintId::of(&unused_unit::UNUSED_UNIT),
 +        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),
 +    ]);
 +
 +    store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
 +        LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
 +        LintId::of(&attrs::DEPRECATED_CFG_ATTR),
 +        LintId::of(&booleans::NONMINIMAL_BOOL),
 +        LintId::of(&double_comparison::DOUBLE_COMPARISONS),
 +        LintId::of(&double_parens::DOUBLE_PARENS),
 +        LintId::of(&duration_subsec::DURATION_SUBSEC),
 +        LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +        LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +        LintId::of(&explicit_write::EXPLICIT_WRITE),
 +        LintId::of(&format::USELESS_FORMAT),
 +        LintId::of(&functions::TOO_MANY_ARGUMENTS),
 +        LintId::of(&get_last_with_len::GET_LAST_WITH_LEN),
 +        LintId::of(&identity_op::IDENTITY_OP),
 +        LintId::of(&int_plus_one::INT_PLUS_ONE),
 +        LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
 +        LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
 +        LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
 +        LintId::of(&loops::MUT_RANGE_BOUND),
 +        LintId::of(&loops::WHILE_LET_LOOP),
 +        LintId::of(&map_identity::MAP_IDENTITY),
 +        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
 +        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
 +        LintId::of(&matches::MATCH_AS_REF),
 +        LintId::of(&matches::MATCH_SINGLE_BINDING),
 +        LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
 +        LintId::of(&methods::BIND_INSTEAD_OF_MAP),
 +        LintId::of(&methods::CLONE_ON_COPY),
 +        LintId::of(&methods::FILTER_NEXT),
 +        LintId::of(&methods::FLAT_MAP_IDENTITY),
 +        LintId::of(&methods::OPTION_AS_REF_DEREF),
 +        LintId::of(&methods::SEARCH_IS_SOME),
 +        LintId::of(&methods::SKIP_WHILE_NEXT),
 +        LintId::of(&methods::SUSPICIOUS_MAP),
 +        LintId::of(&methods::UNNECESSARY_FILTER_MAP),
 +        LintId::of(&methods::USELESS_ASREF),
 +        LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
 +        LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
 +        LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
 +        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_update::NEEDLESS_UPDATE),
 +        LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
 +        LintId::of(&no_effect::NO_EFFECT),
 +        LintId::of(&no_effect::UNNECESSARY_OPERATION),
 +        LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
 +        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +        LintId::of(&precedence::PRECEDENCE),
 +        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +        LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
 +        LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
 +        LintId::of(&reference::DEREF_ADDROF),
 +        LintId::of(&reference::REF_IN_DEREF),
 +        LintId::of(&repeat_once::REPEAT_ONCE),
 +        LintId::of(&swap::MANUAL_SWAP),
 +        LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
 +        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_PTR_TO_PTR),
 +        LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
 +        LintId::of(&types::BORROWED_BOX),
 +        LintId::of(&types::CHAR_LIT_AS_U8),
 +        LintId::of(&types::TYPE_COMPLEXITY),
 +        LintId::of(&types::UNIT_ARG),
 +        LintId::of(&types::UNNECESSARY_CAST),
 +        LintId::of(&types::VEC_BOX),
 +        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +        LintId::of(&unwrap::UNNECESSARY_UNWRAP),
 +        LintId::of(&useless_conversion::USELESS_CONVERSION),
 +        LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +    ]);
 +
 +    store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
 +        LintId::of(&approx_const::APPROX_CONSTANT),
 +        LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
 +        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(&booleans::LOGIC_BUG),
 +        LintId::of(&copies::IFS_SAME_COND),
 +        LintId::of(&copies::IF_SAME_THEN_ELSE),
 +        LintId::of(&derive::DERIVE_HASH_XOR_EQ),
 +        LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +        LintId::of(&drop_bounds::DROP_BOUNDS),
 +        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(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +        LintId::of(&eq_op::EQ_OP),
 +        LintId::of(&erasing_op::ERASING_OP),
++        LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +        LintId::of(&formatting::POSSIBLE_MISSING_COMMA),
 +        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +        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_SHADOW_DISPLAY),
 +        LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +        LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
 +        LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +        LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),
 +        LintId::of(&loops::ITER_NEXT_LOOP),
 +        LintId::of(&loops::NEVER_LOOP),
 +        LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
 +        LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
 +        LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
 +        LintId::of(&methods::CLONE_DOUBLE_REF),
 +        LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
 +        LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR),
 +        LintId::of(&methods::UNINIT_ASSUMED_INIT),
 +        LintId::of(&methods::ZST_OFFSET),
 +        LintId::of(&minmax::MIN_MAX),
 +        LintId::of(&misc::CMP_NAN),
 +        LintId::of(&misc::FLOAT_CMP),
 +        LintId::of(&misc::MODULO_ONE),
 +        LintId::of(&mut_key::MUTABLE_KEY_TYPE),
 +        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +        LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
 +        LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
 +        LintId::of(&ptr::MUT_FROM_REF),
 +        LintId::of(&ranges::REVERSED_EMPTY_RANGES),
 +        LintId::of(&regex::INVALID_REGEX),
++        LintId::of(&self_assignment::SELF_ASSIGNMENT),
 +        LintId::of(&serde_api::SERDE_API_MISUSE),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +        LintId::of(&swap::ALMOST_SWAPPED),
++        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
 +        LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +        LintId::of(&transmute::WRONG_TRANSMUTE),
 +        LintId::of(&transmuting_null::TRANSMUTING_NULL),
 +        LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
 +        LintId::of(&types::CAST_REF_TO_MUT),
 +        LintId::of(&types::UNIT_CMP),
 +        LintId::of(&unicode::ZERO_WIDTH_SPACE),
 +        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +        LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
 +        LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +        LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
 +        LintId::of(&unwrap::PANICKING_UNWRAP),
 +        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +    ]);
 +
 +    store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
 +        LintId::of(&bytecount::NAIVE_BYTECOUNT),
 +        LintId::of(&entry::MAP_ENTRY),
 +        LintId::of(&escape::BOXED_LOCAL),
 +        LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
 +        LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
 +        LintId::of(&loops::MANUAL_MEMCPY),
 +        LintId::of(&loops::NEEDLESS_COLLECT),
 +        LintId::of(&methods::EXPECT_FUN_CALL),
 +        LintId::of(&methods::ITER_NTH),
 +        LintId::of(&methods::OR_FUN_CALL),
 +        LintId::of(&methods::SINGLE_CHAR_PATTERN),
 +        LintId::of(&misc::CMP_OWNED),
 +        LintId::of(&mutex_atomic::MUTEX_ATOMIC),
 +        LintId::of(&redundant_clone::REDUNDANT_CLONE),
 +        LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
 +        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
 +        LintId::of(&types::BOX_VEC),
 +        LintId::of(&types::REDUNDANT_ALLOCATION),
 +        LintId::of(&vec::USELESS_VEC),
 +    ]);
 +
 +    store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
 +        LintId::of(&cargo_common_metadata::CARGO_COMMON_METADATA),
 +        LintId::of(&multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
 +        LintId::of(&wildcard_dependencies::WILDCARD_DEPENDENCIES),
 +    ]);
 +
 +    store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
 +        LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
 +        LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
 +        LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
 +        LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
 +        LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
 +        LintId::of(&future_not_send::FUTURE_NOT_SEND),
 +        LintId::of(&let_if_seq::USELESS_LET_IF_SEQ),
 +        LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN),
 +        LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
 +        LintId::of(&mutex_atomic::MUTEX_INTEGER),
 +        LintId::of(&needless_borrow::NEEDLESS_BORROW),
 +        LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
 +        LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
 +        LintId::of(&transmute::USELESS_TRANSMUTE),
 +        LintId::of(&use_self::USE_SELF),
 +    ]);
 +}
 +
 +#[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(
 +        "str_to_string",
 +        "using `str::to_string` is common even today and specialization will likely happen soon",
 +    );
 +    store.register_removed(
 +        "string_to_string",
 +        "using `string::to_string` is common even today and specialization will likely happen soon",
 +    );
 +    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) {
 +    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::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");
 +}
 +
 +// 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 8ffcd417d1df1848e59a035a3480a28b907e38b6,0000000000000000000000000000000000000000..c95e43a9430446b2470aac5c782c10418b23ac57
mode 100644,000000..100644
--- /dev/null
@@@ -1,2738 -1,0 +1,2758 @@@
-             if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
-                 if let PatKind::Wild = pat.kind {
-                     let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
-                     let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
 +use crate::consts::constant;
 +use crate::utils::paths;
 +use crate::utils::sugg::Sugg;
 +use crate::utils::usage::{is_unused, mutated_variables};
 +use crate::utils::{
 +    get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
 +    is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
 +    match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability,
 +    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
 +    SpanlessEq,
 +};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    def_id, BinOpKind, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, GenericArg, HirId, InlineAsmOperand,
 +    Local, LoopSource, MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind,
 +};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::middle::region;
 +use rustc_middle::ty::{self, Ty, TyS};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{sym, Ident, Symbol};
 +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 +use std::iter::{once, Iterator};
 +use std::mem;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for for-loops that manually copy items between
 +    /// slices that could be optimized by having a memcpy.
 +    ///
 +    /// **Why is this bad?** It is not as fast as a memcpy.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let src = vec![1];
 +    /// # let mut dst = vec![0; 65];
 +    /// for i in 0..src.len() {
 +    ///     dst[i + 64] = src[i];
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// # let src = vec![1];
 +    /// # let mut dst = vec![0; 65];
 +    /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
 +    /// ```
 +    pub MANUAL_MEMCPY,
 +    perf,
 +    "manually copying items between slices"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for looping over the range of `0..len` of some
 +    /// collection just to get the values by index.
 +    ///
 +    /// **Why is this bad?** Just iterating the collection itself makes the intent
 +    /// more clear and is probably faster.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let vec = vec!['a', 'b', 'c'];
 +    /// for i in 0..vec.len() {
 +    ///     println!("{}", vec[i]);
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// let vec = vec!['a', 'b', 'c'];
 +    /// for i in vec {
 +    ///     println!("{}", i);
 +    /// }
 +    /// ```
 +    pub NEEDLESS_RANGE_LOOP,
 +    style,
 +    "for-looping over a range of indices where an iterator over items would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for loops on `x.iter()` where `&x` will do, and
 +    /// suggests the latter.
 +    ///
 +    /// **Why is this bad?** Readability.
 +    ///
 +    /// **Known problems:** False negatives. We currently only warn on some known
 +    /// types.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// // with `y` a `Vec` or slice:
 +    /// # let y = vec![1];
 +    /// for x in y.iter() {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    /// can be rewritten to
 +    /// ```rust
 +    /// # let y = vec![1];
 +    /// for x in &y {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    pub EXPLICIT_ITER_LOOP,
 +    pedantic,
 +    "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for loops on `y.into_iter()` where `y` will do, and
 +    /// suggests the latter.
 +    ///
 +    /// **Why is this bad?** Readability.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let y = vec![1];
 +    /// // with `y` a `Vec` or slice:
 +    /// for x in y.into_iter() {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    /// can be rewritten to
 +    /// ```rust
 +    /// # let y = vec![1];
 +    /// for x in y {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    pub EXPLICIT_INTO_ITER_LOOP,
 +    pedantic,
 +    "for-looping over `_.into_iter()` when `_` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for loops on `x.next()`.
 +    ///
 +    /// **Why is this bad?** `next()` returns either `Some(value)` if there was a
 +    /// value, or `None` otherwise. The insidious thing is that `Option<_>`
 +    /// implements `IntoIterator`, so that possibly one value will be iterated,
 +    /// leading to some hard to find bugs. No one will want to write such code
 +    /// [except to win an Underhanded Rust
 +    /// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// for x in y.next() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub ITER_NEXT_LOOP,
 +    correctness,
 +    "for-looping over `_.next()` which is probably not intended"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `for` loops over `Option` or `Result` values.
 +    ///
 +    /// **Why is this bad?** Readability. This is more clearly expressed as an `if
 +    /// let`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// for x in opt {
 +    ///     // ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// if let Some(x) = opt {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<i32, std::io::Error> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// for x in &res {
 +    ///     // ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// if let Ok(x) = res {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    pub FOR_LOOPS_OVER_FALLIBLES,
 +    correctness,
 +    "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Detects `loop + match` combinations that are easier
 +    /// written as a `while let` loop.
 +    ///
 +    /// **Why is this bad?** The `while let` loop is usually shorter and more
 +    /// readable.
 +    ///
 +    /// **Known problems:** Sometimes the wrong binding is displayed (#383).
 +    ///
 +    /// **Example:**
 +    /// ```rust,no_run
 +    /// # let y = Some(1);
 +    /// loop {
 +    ///     let x = match y {
 +    ///         Some(x) => x,
 +    ///         None => break,
 +    ///     };
 +    ///     // .. do something with x
 +    /// }
 +    /// // is easier written as
 +    /// while let Some(x) = y {
 +    ///     // .. do something with x
 +    /// };
 +    /// ```
 +    pub WHILE_LET_LOOP,
 +    complexity,
 +    "`loop { if let { ... } else break }`, which can be written as a `while let` loop"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for functions collecting an iterator when collect
 +    /// is not needed.
 +    ///
 +    /// **Why is this bad?** `collect` causes the allocation of a new data structure,
 +    /// when this allocation may not be needed.
 +    ///
 +    /// **Known problems:**
 +    /// None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let iterator = vec![1].into_iter();
 +    /// let len = iterator.clone().collect::<Vec<_>>().len();
 +    /// // should be
 +    /// let len = iterator.count();
 +    /// ```
 +    pub NEEDLESS_COLLECT,
 +    perf,
 +    "collecting an iterator when collect is not needed"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks `for` loops over slices with an explicit counter
 +    /// and suggests the use of `.enumerate()`.
 +    ///
 +    /// **Why is it bad?** Using `.enumerate()` makes the intent more clear,
 +    /// declutters the code and may be faster in some instances.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let v = vec![1];
 +    /// # fn bar(bar: usize, baz: usize) {}
 +    /// let mut i = 0;
 +    /// for item in &v {
 +    ///     bar(i, *item);
 +    ///     i += 1;
 +    /// }
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let v = vec![1];
 +    /// # fn bar(bar: usize, baz: usize) {}
 +    /// for (i, item) in v.iter().enumerate() { bar(i, *item); }
 +    /// ```
 +    pub EXPLICIT_COUNTER_LOOP,
 +    complexity,
 +    "for-looping with an explicit counter when `_.enumerate()` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for empty `loop` expressions.
 +    ///
 +    /// **Why is this bad?** Those busy loops burn CPU cycles without doing
 +    /// anything. Think of the environment and either block on something or at least
 +    /// make the thread sleep for some microseconds.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```no_run
 +    /// loop {}
 +    /// ```
 +    pub EMPTY_LOOP,
 +    style,
 +    "empty `loop {}`, which should block or sleep"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `while let` expressions on iterators.
 +    ///
 +    /// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys
 +    /// the intent better.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// while let Some(val) = iter() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub WHILE_LET_ON_ITERATOR,
 +    style,
 +    "using a while-let loop instead of a for loop on an iterator"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for iterating a map (`HashMap` or `BTreeMap`) and
 +    /// ignoring either the keys or values.
 +    ///
 +    /// **Why is this bad?** Readability. There are `keys` and `values` methods that
 +    /// can be used to express that don't need the values or keys.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// for (k, _) in &map {
 +    ///     ..
 +    /// }
 +    /// ```
 +    ///
 +    /// could be replaced by
 +    ///
 +    /// ```ignore
 +    /// for k in map.keys() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub FOR_KV_MAP,
 +    style,
 +    "looping on a map using `iter` when `keys` or `values` would do"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for loops that will always `break`, `return` or
 +    /// `continue` an outer loop.
 +    ///
 +    /// **Why is this bad?** This loop never loops, all it does is obfuscating the
 +    /// code.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// loop {
 +    ///     ..;
 +    ///     break;
 +    /// }
 +    /// ```
 +    pub NEVER_LOOP,
 +    correctness,
 +    "any loop that will always `break` or `return`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for loops which have a range bound that is a mutable variable
 +    ///
 +    /// **Why is this bad?** One might think that modifying the mutable variable changes the loop bounds
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let mut foo = 42;
 +    /// for i in 0..foo {
 +    ///     foo -= 1;
 +    ///     println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
 +    /// }
 +    /// ```
 +    pub MUT_RANGE_BOUND,
 +    complexity,
 +    "for loop over a range where one of the bounds is a mutable variable"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks whether variables used within while loop condition
 +    /// can be (and are) mutated in the body.
 +    ///
 +    /// **Why is this bad?** If the condition is unchanged, entering the body of the loop
 +    /// will lead to an infinite loop.
 +    ///
 +    /// **Known problems:** If the `while`-loop is in a closure, the check for mutation of the
 +    /// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
 +    /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let i = 0;
 +    /// while i > 10 {
 +    ///     println!("let me loop forever!");
 +    /// }
 +    /// ```
 +    pub WHILE_IMMUTABLE_CONDITION,
 +    correctness,
 +    "variables used within while expression are not mutated in the body"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks whether a for loop is being used to push a constant
 +    /// value into a Vec.
 +    ///
 +    /// **Why is this bad?** This kind of operation can be expressed more succinctly with
 +    /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
 +    /// have better performance.
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let item1 = 2;
 +    /// let item2 = 3;
 +    /// let mut vec: Vec<u8> = Vec::new();
 +    /// for _ in 0..20 {
 +    ///    vec.push(item1);
 +    /// }
 +    /// for _ in 0..30 {
 +    ///     vec.push(item2);
 +    /// }
 +    /// ```
 +    /// could be written as
 +    /// ```rust
 +    /// let item1 = 2;
 +    /// let item2 = 3;
 +    /// let mut vec: Vec<u8> = vec![item1; 20];
 +    /// vec.resize(20 + 30, item2);
 +    /// ```
 +    pub SAME_ITEM_PUSH,
 +    style,
 +    "the same item is pushed inside of a for loop"
 +}
 +
 +declare_lint_pass!(Loops => [
 +    MANUAL_MEMCPY,
 +    NEEDLESS_RANGE_LOOP,
 +    EXPLICIT_ITER_LOOP,
 +    EXPLICIT_INTO_ITER_LOOP,
 +    ITER_NEXT_LOOP,
 +    FOR_LOOPS_OVER_FALLIBLES,
 +    WHILE_LET_LOOP,
 +    NEEDLESS_COLLECT,
 +    EXPLICIT_COUNTER_LOOP,
 +    EMPTY_LOOP,
 +    WHILE_LET_ON_ITERATOR,
 +    FOR_KV_MAP,
 +    NEVER_LOOP,
 +    MUT_RANGE_BOUND,
 +    WHILE_IMMUTABLE_CONDITION,
 +    SAME_ITEM_PUSH,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Loops {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let Some((pat, arg, body)) = higher::for_loop(expr) {
 +            // we don't want to check expanded macros
 +            // this check is not at the top of the function
 +            // since higher::for_loop expressions are marked as expansions
 +            if body.span.from_expansion() {
 +                return;
 +            }
 +            check_for_loop(cx, pat, arg, body, expr);
 +        }
 +
 +        // we don't want to check expanded macros
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        // check for never_loop
 +        if let ExprKind::Loop(ref block, _, _) = expr.kind {
 +            match never_loop_block(block, expr.hir_id) {
 +                NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
 +                NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
 +            }
 +        }
 +
 +        // check for `loop { if let {} else break }` that could be `while let`
 +        // (also matches an explicit "match" instead of "if let")
 +        // (even if the "match" or "if let" is used for declaration)
 +        if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
 +            // also check for empty `loop {}` statements
 +            if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) {
 +                span_lint(
 +                    cx,
 +                    EMPTY_LOOP,
 +                    expr.span,
 +                    "empty `loop {}` detected. You may want to either use `panic!()` or add \
 +                     `std::thread::sleep(..);` to the loop body.",
 +                );
 +            }
 +
 +            // extract the expression from the first statement (if any) in a block
 +            let inner_stmt_expr = extract_expr_from_first_stmt(block);
 +            // or extract the first expression (if any) from the block
 +            if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(block)) {
 +                if let ExprKind::Match(ref matchexpr, ref arms, ref source) = inner.kind {
 +                    // ensure "if let" compatible match structure
 +                    match *source {
 +                        MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
 +                            if arms.len() == 2
 +                                && arms[0].guard.is_none()
 +                                && arms[1].guard.is_none()
 +                                && is_simple_break_expr(&arms[1].body)
 +                            {
 +                                if in_external_macro(cx.sess(), expr.span) {
 +                                    return;
 +                                }
 +
 +                                // NOTE: we used to build a body here instead of using
 +                                // ellipsis, this was removed because:
 +                                // 1) it was ugly with big bodies;
 +                                // 2) it was not indented properly;
 +                                // 3) it wasn’t very smart (see #675).
 +                                let mut applicability = Applicability::HasPlaceholders;
 +                                span_lint_and_sugg(
 +                                    cx,
 +                                    WHILE_LET_LOOP,
 +                                    expr.span,
 +                                    "this loop could be written as a `while let` loop",
 +                                    "try",
 +                                    format!(
 +                                        "while let {} = {} {{ .. }}",
 +                                        snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability),
 +                                        snippet_with_applicability(cx, matchexpr.span, "..", &mut applicability),
 +                                    ),
 +                                    applicability,
 +                                );
 +                            }
 +                        },
 +                        _ => (),
 +                    }
 +                }
 +            }
 +        }
 +        if let ExprKind::Match(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.kind {
 +            let pat = &arms[0].pat.kind;
 +            if let (
 +                &PatKind::TupleStruct(ref qpath, ref pat_args, _),
 +                &ExprKind::MethodCall(ref method_path, _, ref method_args, _),
 +            ) = (pat, &match_expr.kind)
 +            {
 +                let iter_expr = &method_args[0];
 +
 +                // Don't lint when the iterator is recreated on every iteration
 +                if_chain! {
 +                    if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
 +                    if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR);
 +                    if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]);
 +                    then {
 +                        return;
 +                    }
 +                }
 +
 +                let lhs_constructor = last_path_segment(qpath);
 +                if method_path.ident.name == sym!(next)
 +                    && match_trait_method(cx, match_expr, &paths::ITERATOR)
 +                    && lhs_constructor.ident.name == sym!(Some)
 +                    && (pat_args.is_empty()
 +                        || !is_refutable(cx, &pat_args[0])
 +                            && !is_used_inside(cx, iter_expr, &arms[0].body)
 +                            && !is_iterator_used_after_while_let(cx, iter_expr)
 +                            && !is_nested(cx, expr, &method_args[0]))
 +                {
 +                    let mut applicability = Applicability::MachineApplicable;
 +                    let iterator = snippet_with_applicability(cx, method_args[0].span, "_", &mut applicability);
 +                    let loop_var = if pat_args.is_empty() {
 +                        "_".to_string()
 +                    } else {
 +                        snippet_with_applicability(cx, pat_args[0].span, "_", &mut applicability).into_owned()
 +                    };
 +                    span_lint_and_sugg(
 +                        cx,
 +                        WHILE_LET_ON_ITERATOR,
 +                        expr.span.with_hi(match_expr.span.hi()),
 +                        "this loop could be written as a `for` loop",
 +                        "try",
 +                        format!("for {} in {}", loop_var, iterator),
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +
 +        if let Some((cond, body)) = higher::while_loop(&expr) {
 +            check_infinite_loop(cx, cond, body);
 +        }
 +
 +        check_needless_collect(expr, cx);
 +    }
 +}
 +
 +enum NeverLoopResult {
 +    // A break/return always get triggered but not necessarily for the main loop.
 +    AlwaysBreak,
 +    // A continue may occur for the main loop.
 +    MayContinueMainLoop,
 +    Otherwise,
 +}
 +
 +#[must_use]
 +fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
 +    match *arg {
 +        NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
 +        NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
 +    }
 +}
 +
 +// Combine two results for parts that are called in order.
 +#[must_use]
 +fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
 +    match first {
 +        NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
 +        NeverLoopResult::Otherwise => second,
 +    }
 +}
 +
 +// Combine two results where both parts are called but not necessarily in order.
 +#[must_use]
 +fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
 +    match (left, right) {
 +        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
 +            NeverLoopResult::MayContinueMainLoop
 +        },
 +        (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
 +        (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
 +    }
 +}
 +
 +// Combine two results where only one of the part may have been executed.
 +#[must_use]
 +fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
 +    match (b1, b2) {
 +        (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
 +        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
 +            NeverLoopResult::MayContinueMainLoop
 +        },
 +        (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
 +    }
 +}
 +
 +fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
 +    let stmts = block.stmts.iter().map(stmt_to_expr);
 +    let expr = once(block.expr.as_deref());
 +    let mut iter = stmts.chain(expr).filter_map(|e| e);
 +    never_loop_expr_seq(&mut iter, main_loop_id)
 +}
 +
 +fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    match stmt.kind {
 +        StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
 +        StmtKind::Local(ref local) => local.init.as_deref(),
 +        _ => None,
 +    }
 +}
 +
 +fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
 +    match expr.kind {
 +        ExprKind::Box(ref e)
 +        | ExprKind::Unary(_, ref e)
 +        | ExprKind::Cast(ref e, _)
 +        | ExprKind::Type(ref e, _)
 +        | ExprKind::Field(ref e, _)
 +        | ExprKind::AddrOf(_, _, ref e)
 +        | ExprKind::Struct(_, _, Some(ref e))
 +        | ExprKind::Repeat(ref e, _)
 +        | ExprKind::DropTemps(ref e) => never_loop_expr(e, main_loop_id),
 +        ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es, _) | ExprKind::Tup(ref es) => {
 +            never_loop_expr_all(&mut es.iter(), main_loop_id)
 +        },
 +        ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
 +        ExprKind::Binary(_, ref e1, ref e2)
 +        | ExprKind::Assign(ref e1, ref e2, _)
 +        | ExprKind::AssignOp(_, ref e1, ref e2)
 +        | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
 +        ExprKind::Loop(ref b, _, _) => {
 +            // Break can come from the inner loop so remove them.
 +            absorb_break(&never_loop_block(b, main_loop_id))
 +        },
 +        ExprKind::Match(ref e, ref arms, _) => {
 +            let e = never_loop_expr(e, main_loop_id);
 +            if arms.is_empty() {
 +                e
 +            } else {
 +                let arms = never_loop_expr_branch(&mut arms.iter().map(|a| &*a.body), main_loop_id);
 +                combine_seq(e, arms)
 +            }
 +        },
 +        ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id),
 +        ExprKind::Continue(d) => {
 +            let id = d
 +                .target_id
 +                .expect("target ID can only be missing in the presence of compilation errors");
 +            if id == main_loop_id {
 +                NeverLoopResult::MayContinueMainLoop
 +            } else {
 +                NeverLoopResult::AlwaysBreak
 +            }
 +        },
 +        ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
 +            combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
 +        }),
 +        ExprKind::InlineAsm(ref asm) => asm
 +            .operands
 +            .iter()
 +            .map(|o| match o {
 +                InlineAsmOperand::In { expr, .. }
 +                | InlineAsmOperand::InOut { expr, .. }
 +                | InlineAsmOperand::Const { expr }
 +                | InlineAsmOperand::Sym { expr } => never_loop_expr(expr, main_loop_id),
 +                InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
 +                InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
 +                    never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
 +                },
 +            })
 +            .fold(NeverLoopResult::Otherwise, combine_both),
 +        ExprKind::Struct(_, _, None)
 +        | ExprKind::Yield(_, _)
 +        | ExprKind::Closure(_, _, _, _, _)
 +        | ExprKind::LlvmInlineAsm(_)
 +        | ExprKind::Path(_)
 +        | ExprKind::Lit(_)
 +        | ExprKind::Err => NeverLoopResult::Otherwise,
 +    }
 +}
 +
 +fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
 +    es.map(|e| never_loop_expr(e, main_loop_id))
 +        .fold(NeverLoopResult::Otherwise, combine_seq)
 +}
 +
 +fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
 +    es.map(|e| never_loop_expr(e, main_loop_id))
 +        .fold(NeverLoopResult::Otherwise, combine_both)
 +}
 +
 +fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_loop_id: HirId) -> NeverLoopResult {
 +    e.map(|e| never_loop_expr(e, main_loop_id))
 +        .fold(NeverLoopResult::AlwaysBreak, combine_branches)
 +}
 +
 +fn check_for_loop<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
 +    check_for_loop_range(cx, pat, arg, body, expr);
 +    check_for_loop_arg(cx, pat, arg, expr);
 +    check_for_loop_explicit_counter(cx, pat, arg, body, expr);
 +    check_for_loop_over_map_kv(cx, pat, arg, body, expr);
 +    check_for_mut_range_bound(cx, arg, body);
 +    detect_manual_memcpy(cx, pat, arg, body, expr);
 +    detect_same_item_push(cx, pat, arg, body, expr);
 +}
 +
 +fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
 +    if_chain! {
 +        if let ExprKind::Path(qpath) = &expr.kind;
 +        if let QPath::Resolved(None, path) = qpath;
 +        if path.segments.len() == 1;
 +        if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
 +        then {
 +            // our variable!
 +            local_id == var
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OffsetSign {
 +    Positive,
 +    Negative,
 +}
 +
 +struct Offset {
 +    value: String,
 +    sign: OffsetSign,
 +}
 +
 +impl Offset {
 +    fn negative(value: String) -> Self {
 +        Self {
 +            value,
 +            sign: OffsetSign::Negative,
 +        }
 +    }
 +
 +    fn positive(value: String) -> Self {
 +        Self {
 +            value,
 +            sign: OffsetSign::Positive,
 +        }
 +    }
 +}
 +
 +struct FixedOffsetVar<'hir> {
 +    var: &'hir Expr<'hir>,
 +    offset: Offset,
 +}
 +
 +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_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
 +}
 +
 +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_offset<'tcx>(cx: &LateContext<'tcx>, idx: &Expr<'_>, var: HirId) -> Option<Offset> {
 +    fn extract_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, var: HirId) -> Option<String> {
 +        match &e.kind {
 +            ExprKind::Lit(l) => match l.node {
 +                ast::LitKind::Int(x, _ty) => Some(x.to_string()),
 +                _ => None,
 +            },
 +            ExprKind::Path(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())),
 +            _ => None,
 +        }
 +    }
 +
 +    match idx.kind {
 +        ExprKind::Binary(op, lhs, rhs) => match op.node {
 +            BinOpKind::Add => {
 +                let offset_opt = if same_var(cx, lhs, var) {
 +                    extract_offset(cx, rhs, var)
 +                } else if same_var(cx, rhs, var) {
 +                    extract_offset(cx, lhs, var)
 +                } else {
 +                    None
 +                };
 +
 +                offset_opt.map(Offset::positive)
 +            },
 +            BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
 +            _ => None,
 +        },
 +        ExprKind::Path(..) if same_var(cx, idx, var) => Some(Offset::positive("0".into())),
 +        _ => None,
 +    }
 +}
 +
 +fn get_assignments<'tcx>(body: &'tcx Expr<'tcx>) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> {
 +    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
 +        }
 +    }
 +
 +    // 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(b, _) = body.kind {
 +        let Block { stmts, expr, .. } = *b;
 +
 +        iter_a = stmts
 +            .iter()
 +            .filter_map(|stmt| match stmt.kind {
 +                StmtKind::Local(..) | StmtKind::Item(..) => None,
 +                StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
 +            })
 +            .chain(expr.into_iter())
 +            .map(get_assignment)
 +            .into()
 +    } else {
 +        iter_b = Some(get_assignment(body))
 +    }
 +
 +    iter_a.into_iter().flatten().chain(iter_b.into_iter())
 +}
 +
 +fn build_manual_memcpy_suggestion<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    start: &Expr<'_>,
 +    end: &Expr<'_>,
 +    limits: ast::RangeLimits,
 +    dst_var: FixedOffsetVar<'_>,
 +    src_var: FixedOffsetVar<'_>,
 +) -> String {
 +    fn print_sum(arg1: &str, arg2: &Offset) -> String {
 +        match (arg1, &arg2.value[..], arg2.sign) {
 +            ("0", "0", _) => "0".into(),
 +            ("0", x, OffsetSign::Positive) | (x, "0", _) => x.into(),
 +            ("0", x, OffsetSign::Negative) => format!("-{}", x),
 +            (x, y, OffsetSign::Positive) => format!("({} + {})", x, y),
 +            (x, y, OffsetSign::Negative) => {
 +                if x == y {
 +                    "0".into()
 +                } else {
 +                    format!("({} - {})", x, y)
 +                }
 +            },
 +        }
 +    }
 +
 +    fn print_offset(start_str: &str, inline_offset: &Offset) -> String {
 +        let offset = print_sum(start_str, inline_offset);
 +        if offset.as_str() == "0" {
 +            "".into()
 +        } else {
 +            offset
 +        }
 +    }
 +
 +    let print_limit = |end: &Expr<'_>, offset: Offset, var: &Expr<'_>| {
 +        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 var_def_id(cx, arg) == var_def_id(cx, var);
 +            then {
 +                match offset.sign {
 +                    OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value),
 +                    OffsetSign::Positive => "".into(),
 +                }
 +            } else {
 +                let end_str = match limits {
 +                    ast::RangeLimits::Closed => {
 +                        let end = sugg::Sugg::hir(cx, end, "<count>");
 +                        format!("{}", end + sugg::ONE)
 +                    },
 +                    ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
 +                };
 +
 +                print_sum(&end_str, &offset)
 +            }
 +        }
 +    };
 +
 +    let start_str = snippet(cx, start.span, "").to_string();
 +    let dst_offset = print_offset(&start_str, &dst_var.offset);
 +    let dst_limit = print_limit(end, dst_var.offset, dst_var.var);
 +    let src_offset = print_offset(&start_str, &src_var.offset);
 +    let src_limit = print_limit(end, src_var.offset, src_var.var);
 +
 +    let dst_var_name = snippet_opt(cx, dst_var.var.span).unwrap_or_else(|| "???".into());
 +    let src_var_name = snippet_opt(cx, src_var.var.span).unwrap_or_else(|| "???".into());
 +
 +    let dst = if dst_offset == "" && dst_limit == "" {
 +        dst_var_name
 +    } else {
 +        format!("{}[{}..{}]", dst_var_name, dst_offset, dst_limit)
 +    };
 +
 +    format!(
 +        "{}.clone_from_slice(&{}[{}..{}])",
 +        dst, src_var_name, src_offset, src_limit
 +    )
 +}
 +/// Checks for for loops that sequentially copy items from one slice-like
 +/// object to another.
 +fn detect_manual_memcpy<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
 +    if let Some(higher::Range {
 +        start: Some(start),
 +        end: Some(end),
 +        limits,
 +    }) = higher::range(arg)
 +    {
 +        // the var must be a single name
 +        if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
 +            // The only statements in the for loops can be indexed assignments from
 +            // indexed retrievals.
 +            let big_sugg = get_assignments(body)
 +                .map(|o| {
 +                    o.and_then(|(lhs, rhs)| {
 +                        let rhs = fetch_cloned_expr(rhs);
 +                        if_chain! {
 +                            if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
 +                            if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
 +                            if is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_left))
 +                                && is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_right));
 +                            if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
 +                            if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
 +
 +                            // Source and destination must be different
 +                            if var_def_id(cx, seqexpr_left) != var_def_id(cx, seqexpr_right);
 +                            then {
 +                                Some((FixedOffsetVar { var: seqexpr_left, offset: offset_left },
 +                                    FixedOffsetVar { var: seqexpr_right, 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,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +// Scans the body of the for loop and determines whether lint should be given
 +struct SameItemPushVisitor<'a, 'tcx> {
 +    should_lint: bool,
 +    // this field holds the last vec push operation visited, which should be the only push seen
 +    vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        match &expr.kind {
 +            // Non-determinism may occur ... don't give a lint
 +            ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false,
 +            ExprKind::Block(block, _) => self.visit_block(block),
 +            _ => {},
 +        }
 +    }
 +
 +    fn visit_block(&mut self, b: &'tcx Block<'_>) {
 +        for stmt in b.stmts.iter() {
 +            self.visit_stmt(stmt);
 +        }
 +    }
 +
 +    fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) {
 +        let vec_push_option = get_vec_push(self.cx, s);
 +        if vec_push_option.is_none() {
 +            // Current statement is not a push so visit inside
 +            match &s.kind {
 +                StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(&expr),
 +                _ => {},
 +            }
 +        } else {
 +            // Current statement is a push ...check whether another
 +            // push had been previously done
 +            if self.vec_push.is_none() {
 +                self.vec_push = vec_push_option;
 +            } else {
 +                // There are multiple pushes ... don't lint
 +                self.should_lint = false;
 +            }
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +// Given some statement, determine if that statement is a push on a Vec. If it is, return
 +// the Vec being pushed into and the item being pushed
 +fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
 +    if_chain! {
 +            // Extract method being called
 +            if let StmtKind::Semi(semi_stmt) = &stmt.kind;
 +            if let ExprKind::MethodCall(path, _, args, _) = &semi_stmt.kind;
 +            // Figure out the parameters for the method call
 +            if let Some(self_expr) = args.get(0);
 +            if let Some(pushed_item) = args.get(1);
 +            // Check that the method being called is push() on a Vec
 +            if match_type(cx, cx.typeck_results().expr_ty(self_expr), &paths::VEC);
 +            if path.ident.name.as_str() == "push";
 +            then {
 +                return Some((self_expr, pushed_item))
 +            }
 +    }
 +    None
 +}
 +
 +/// Detects for loop pushing the same item into a Vec
 +fn detect_same_item_push<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    _: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    _: &'tcx Expr<'_>,
 +) {
 +    // Determine whether it is safe to lint the body
 +    let mut same_item_push_visitor = SameItemPushVisitor {
 +        should_lint: true,
 +        vec_push: None,
 +        cx,
 +    };
 +    walk_expr(&mut same_item_push_visitor, body);
 +    if same_item_push_visitor.should_lint {
 +        if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push {
 +            // Make sure that the push does not involve possibly mutating values
++            if let PatKind::Wild = pat.kind {
++                let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
++                let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
++                if let ExprKind::Path(ref qpath) = pushed_item.kind {
++                    if_chain! {
++                        if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id);
++                        let node = cx.tcx.hir().get(hir_id);
++                        if let Node::Binding(pat) = node;
++                        if let PatKind::Binding(bind_ann, ..) = pat.kind;
++                        if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
++                        then {
++                            span_lint_and_help(
++                                cx,
++                                SAME_ITEM_PUSH,
++                                vec.span,
++                                "it looks like the same item is being pushed into this Vec",
++                                None,
++                                &format!(
++                                    "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
++                                    item_str, vec_str, item_str
++                                ),
++                            )
++                        }
++                    }
++                } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) {
 +                    span_lint_and_help(
 +                        cx,
 +                        SAME_ITEM_PUSH,
 +                        vec.span,
 +                        "it looks like the same item is being pushed into this Vec",
 +                        None,
 +                        &format!(
 +                            "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
 +                            item_str, vec_str, item_str
 +                        ),
 +                    )
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Checks for looping over a range and then indexing a sequence with it.
 +/// The iteratee must be a range literal.
 +#[allow(clippy::too_many_lines)]
 +fn check_for_loop_range<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
 +    if let Some(higher::Range {
 +        start: Some(start),
 +        ref end,
 +        limits,
 +    }) = higher::range(arg)
 +    {
 +        // the var must be a single name
 +        if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
 +            let mut visitor = VarVisitor {
 +                cx,
 +                var: canonical_id,
 +                indexed_mut: FxHashSet::default(),
 +                indexed_indirectly: FxHashMap::default(),
 +                indexed_directly: FxHashMap::default(),
 +                referenced: FxHashSet::default(),
 +                nonindex: false,
 +                prefer_mutable: false,
 +            };
 +            walk_expr(&mut visitor, body);
 +
 +            // linting condition: we only indexed one variable, and indexed it directly
 +            if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 {
 +                let (indexed, (indexed_extent, indexed_ty)) = visitor
 +                    .indexed_directly
 +                    .into_iter()
 +                    .next()
 +                    .expect("already checked that we have exactly 1 element");
 +
 +                // ensure that the indexed variable was declared before the loop, see #601
 +                if let Some(indexed_extent) = indexed_extent {
 +                    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
 +                    let parent_def_id = cx.tcx.hir().local_def_id(parent_id);
 +                    let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
 +                    let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id);
 +                    if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
 +                        return;
 +                    }
 +                }
 +
 +                // don't lint if the container that is indexed does not have .iter() method
 +                let has_iter = has_iter_method(cx, indexed_ty);
 +                if has_iter.is_none() {
 +                    return;
 +                }
 +
 +                // don't lint if the container that is indexed into is also used without
 +                // indexing
 +                if visitor.referenced.contains(&indexed) {
 +                    return;
 +                }
 +
 +                let starts_at_zero = is_integer_const(cx, start, 0);
 +
 +                let skip = if starts_at_zero {
 +                    String::new()
 +                } else {
 +                    format!(".skip({})", snippet(cx, start.span, ".."))
 +                };
 +
 +                let mut end_is_start_plus_val = false;
 +
 +                let take = if let Some(end) = *end {
 +                    let mut take_expr = end;
 +
 +                    if let ExprKind::Binary(ref op, ref left, ref right) = end.kind {
 +                        if let BinOpKind::Add = op.node {
 +                            let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
 +                            let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
 +
 +                            if start_equal_left {
 +                                take_expr = right;
 +                            } else if start_equal_right {
 +                                take_expr = left;
 +                            }
 +
 +                            end_is_start_plus_val = start_equal_left | start_equal_right;
 +                        }
 +                    }
 +
 +                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
 +                        String::new()
 +                    } else {
 +                        match limits {
 +                            ast::RangeLimits::Closed => {
 +                                let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
 +                                format!(".take({})", take_expr + sugg::ONE)
 +                            },
 +                            ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, take_expr.span, "..")),
 +                        }
 +                    }
 +                } else {
 +                    String::new()
 +                };
 +
 +                let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) {
 +                    ("mut ", "iter_mut")
 +                } else {
 +                    ("", "iter")
 +                };
 +
 +                let take_is_empty = take.is_empty();
 +                let mut method_1 = take;
 +                let mut method_2 = skip;
 +
 +                if end_is_start_plus_val {
 +                    mem::swap(&mut method_1, &mut method_2);
 +                }
 +
 +                if visitor.nonindex {
 +                    span_lint_and_then(
 +                        cx,
 +                        NEEDLESS_RANGE_LOOP,
 +                        expr.span,
 +                        &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
 +                        |diag| {
 +                            multispan_sugg(
 +                                diag,
 +                                "consider using an iterator",
 +                                vec![
 +                                    (pat.span, format!("({}, <item>)", ident.name)),
 +                                    (
 +                                        arg.span,
 +                                        format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
 +                                    ),
 +                                ],
 +                            );
 +                        },
 +                    );
 +                } else {
 +                    let repl = if starts_at_zero && take_is_empty {
 +                        format!("&{}{}", ref_mut, indexed)
 +                    } else {
 +                        format!("{}.{}(){}{}", indexed, method, method_1, method_2)
 +                    };
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        NEEDLESS_RANGE_LOOP,
 +                        expr.span,
 +                        &format!(
 +                            "the loop variable `{}` is only used to index `{}`.",
 +                            ident.name, indexed
 +                        ),
 +                        |diag| {
 +                            multispan_sugg(
 +                                diag,
 +                                "consider using an iterator",
 +                                vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
 +                            );
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
 +    if_chain! {
 +        if let ExprKind::MethodCall(ref method, _, ref len_args, _) = expr.kind;
 +        if len_args.len() == 1;
 +        if method.ident.name == sym!(len);
 +        if let ExprKind::Path(QPath::Resolved(_, ref path)) = len_args[0].kind;
 +        if path.segments.len() == 1;
 +        if path.segments[0].ident.name == var;
 +        then {
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn is_end_eq_array_len<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    end: &Expr<'_>,
 +    limits: ast::RangeLimits,
 +    indexed_ty: Ty<'tcx>,
 +) -> bool {
 +    if_chain! {
 +        if let ExprKind::Lit(ref lit) = end.kind;
 +        if let ast::LitKind::Int(end_int, _) = lit.node;
 +        if let ty::Array(_, arr_len_const) = indexed_ty.kind;
 +        if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env);
 +        then {
 +            return match limits {
 +                ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
 +                ast::RangeLimits::HalfOpen => end_int >= arr_len.into(),
 +            };
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn lint_iter_method(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) {
 +    let mut applicability = Applicability::MachineApplicable;
 +    let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
 +    let muta = if method_name == "iter_mut" { "mut " } else { "" };
 +    span_lint_and_sugg(
 +        cx,
 +        EXPLICIT_ITER_LOOP,
 +        arg.span,
 +        "it is more concise to loop over references to containers instead of using explicit \
 +         iteration methods",
 +        "to write this more concisely, try",
 +        format!("&{}{}", muta, object),
 +        applicability,
 +    )
 +}
 +
 +fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) {
 +    let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
 +    if let ExprKind::MethodCall(ref method, _, ref args, _) = arg.kind {
 +        // just the receiver, no arguments
 +        if args.len() == 1 {
 +            let method_name = &*method.ident.as_str();
 +            // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
 +            if method_name == "iter" || method_name == "iter_mut" {
 +                if is_ref_iterable_type(cx, &args[0]) {
 +                    lint_iter_method(cx, args, arg, method_name);
 +                }
 +            } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
 +                let receiver_ty = cx.typeck_results().expr_ty(&args[0]);
 +                let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]);
 +                if TyS::same_type(receiver_ty, receiver_ty_adjusted) {
 +                    let mut applicability = Applicability::MachineApplicable;
 +                    let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
 +                    span_lint_and_sugg(
 +                        cx,
 +                        EXPLICIT_INTO_ITER_LOOP,
 +                        arg.span,
 +                        "it is more concise to loop over containers instead of using explicit \
 +                         iteration methods",
 +                        "to write this more concisely, try",
 +                        object.to_string(),
 +                        applicability,
 +                    );
 +                } else {
 +                    let ref_receiver_ty = cx.tcx.mk_ref(
 +                        cx.tcx.lifetimes.re_erased,
 +                        ty::TypeAndMut {
 +                            ty: receiver_ty,
 +                            mutbl: Mutability::Not,
 +                        },
 +                    );
 +                    if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) {
 +                        lint_iter_method(cx, args, arg, method_name)
 +                    }
 +                }
 +            } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) {
 +                span_lint(
 +                    cx,
 +                    ITER_NEXT_LOOP,
 +                    expr.span,
 +                    "you are iterating over `Iterator::next()` which is an Option; this will compile but is \
 +                    probably not what you want",
 +                );
 +                next_loop_linted = true;
 +            }
 +        }
 +    }
 +    if !next_loop_linted {
 +        check_arg_type(cx, pat, arg);
 +    }
 +}
 +
 +/// Checks for `for` loops over `Option`s and `Result`s.
 +fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
 +    let ty = cx.typeck_results().expr_ty(arg);
 +    if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
 +        span_lint_and_help(
 +            cx,
 +            FOR_LOOPS_OVER_FALLIBLES,
 +            arg.span,
 +            &format!(
 +                "for loop over `{0}`, which is an `Option`. This is more readably written as an \
 +                `if let` statement.",
 +                snippet(cx, arg.span, "_")
 +            ),
 +            None,
 +            &format!(
 +                "consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
 +                snippet(cx, pat.span, "_"),
 +                snippet(cx, arg.span, "_")
 +            ),
 +        );
 +    } else if is_type_diagnostic_item(cx, ty, sym!(result_type)) {
 +        span_lint_and_help(
 +            cx,
 +            FOR_LOOPS_OVER_FALLIBLES,
 +            arg.span,
 +            &format!(
 +                "for loop over `{0}`, which is a `Result`. This is more readably written as an \
 +                `if let` statement.",
 +                snippet(cx, arg.span, "_")
 +            ),
 +            None,
 +            &format!(
 +                "consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`",
 +                snippet(cx, pat.span, "_"),
 +                snippet(cx, arg.span, "_")
 +            ),
 +        );
 +    }
 +}
 +
 +fn check_for_loop_explicit_counter<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
 +    // Look for variables that are incremented once per loop iteration.
 +    let mut visitor = IncrementVisitor {
 +        cx,
 +        states: FxHashMap::default(),
 +        depth: 0,
 +        done: false,
 +    };
 +    walk_expr(&mut visitor, body);
 +
 +    // For each candidate, check the parent block to see if
 +    // it's initialized to zero at the start of the loop.
 +    if let Some(block) = get_enclosing_block(&cx, expr.hir_id) {
 +        for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) {
 +            let mut visitor2 = InitializeVisitor {
 +                cx,
 +                end_expr: expr,
 +                var_id: *id,
 +                state: VarState::IncrOnce,
 +                name: None,
 +                depth: 0,
 +                past_loop: false,
 +            };
 +            walk_block(&mut visitor2, block);
 +
 +            if visitor2.state == VarState::Warn {
 +                if let Some(name) = visitor2.name {
 +                    let mut applicability = Applicability::MachineApplicable;
 +
 +                    // for some reason this is the only way to get the `Span`
 +                    // of the entire `for` loop
 +                    let for_span = if let ExprKind::Match(_, arms, _) = &expr.kind {
 +                        arms[0].body.span
 +                    } else {
 +                        unreachable!()
 +                    };
 +
 +                    span_lint_and_sugg(
 +                        cx,
 +                        EXPLICIT_COUNTER_LOOP,
 +                        for_span.with_hi(arg.span.hi()),
 +                        &format!("the variable `{}` is used as a loop counter.", name),
 +                        "consider using",
 +                        format!(
 +                            "for ({}, {}) in {}.enumerate()",
 +                            name,
 +                            snippet_with_applicability(cx, pat.span, "item", &mut applicability),
 +                            make_iterator_snippet(cx, arg, &mut applicability),
 +                        ),
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 +/// actual `Iterator` that the loop uses.
 +fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
 +    let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |id| {
 +        implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
 +    });
 +    if impls_iterator {
 +        format!(
 +            "{}",
 +            sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +        )
 +    } else {
 +        // (&x).into_iter() ==> x.iter()
 +        // (&mut x).into_iter() ==> x.iter_mut()
 +        match &arg.kind {
 +            ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
 +                if has_iter_method(cx, cx.typeck_results().expr_ty(&arg_inner)).is_some() =>
 +            {
 +                let meth_name = match mutability {
 +                    Mutability::Mut => "iter_mut",
 +                    Mutability::Not => "iter",
 +                };
 +                format!(
 +                    "{}.{}()",
 +                    sugg::Sugg::hir_with_applicability(cx, &arg_inner, "_", applic_ref).maybe_par(),
 +                    meth_name,
 +                )
 +            }
 +            _ => format!(
 +                "{}.into_iter()",
 +                sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +            ),
 +        }
 +    }
 +}
 +
 +/// Checks for the `FOR_KV_MAP` lint.
 +fn check_for_loop_over_map_kv<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
 +    let pat_span = pat.span;
 +
 +    if let PatKind::Tuple(ref pat, _) = pat.kind {
 +        if pat.len() == 2 {
 +            let arg_span = arg.span;
 +            let (new_pat_span, kind, ty, mutbl) = match cx.typeck_results().expr_ty(arg).kind {
 +                ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
 +                    (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
 +                    (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
 +                    _ => return,
 +                },
 +                _ => return,
 +            };
 +            let mutbl = match mutbl {
 +                Mutability::Not => "",
 +                Mutability::Mut => "_mut",
 +            };
 +            let arg = match arg.kind {
 +                ExprKind::AddrOf(BorrowKind::Ref, _, ref expr) => &**expr,
 +                _ => arg,
 +            };
 +
 +            if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP) {
 +                span_lint_and_then(
 +                    cx,
 +                    FOR_KV_MAP,
 +                    expr.span,
 +                    &format!("you seem to want to iterate on a map's {}s", kind),
 +                    |diag| {
 +                        let map = sugg::Sugg::hir(cx, arg, "map");
 +                        multispan_sugg(
 +                            diag,
 +                            "use the corresponding method",
 +                            vec![
 +                                (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
 +                                (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)),
 +                            ],
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +struct MutatePairDelegate<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    hir_id_low: Option<HirId>,
 +    hir_id_high: Option<HirId>,
 +    span_low: Option<Span>,
 +    span_high: Option<Span>,
 +}
 +
 +impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
 +    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
 +
 +    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
 +        if let ty::BorrowKind::MutBorrow = bk {
 +            if let PlaceBase::Local(id) = cmt.place.base {
 +                if Some(id) == self.hir_id_low {
 +                    self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
 +                }
 +                if Some(id) == self.hir_id_high {
 +                    self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
 +                }
 +            }
 +        }
 +    }
 +
 +    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
 +        if let PlaceBase::Local(id) = cmt.place.base {
 +            if Some(id) == self.hir_id_low {
 +                self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
 +            }
 +            if Some(id) == self.hir_id_high {
 +                self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
 +            }
 +        }
 +    }
 +}
 +
 +impl MutatePairDelegate<'_, '_> {
 +    fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
 +        (self.span_low, self.span_high)
 +    }
 +}
 +
 +fn check_for_mut_range_bound(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
 +    if let Some(higher::Range {
 +        start: Some(start),
 +        end: Some(end),
 +        ..
 +    }) = higher::range(arg)
 +    {
 +        let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
 +        if mut_ids[0].is_some() || mut_ids[1].is_some() {
 +            let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
 +            mut_warn_with_span(cx, span_low);
 +            mut_warn_with_span(cx, span_high);
 +        }
 +    }
 +}
 +
 +fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
 +    if let Some(sp) = span {
 +        span_lint(
 +            cx,
 +            MUT_RANGE_BOUND,
 +            sp,
 +            "attempt to mutate range bound within loop; note that the range of the loop is unchanged",
 +        );
 +    }
 +}
 +
 +fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
 +    if_chain! {
 +        if let ExprKind::Path(ref qpath) = bound.kind;
 +        if let QPath::Resolved(None, _) = *qpath;
 +        then {
 +            let res = qpath_res(cx, qpath, bound.hir_id);
 +            if let Res::Local(hir_id) = res {
 +                let node_str = cx.tcx.hir().get(hir_id);
 +                if_chain! {
 +                    if let Node::Binding(pat) = node_str;
 +                    if let PatKind::Binding(bind_ann, ..) = pat.kind;
 +                    if let BindingAnnotation::Mutable = bind_ann;
 +                    then {
 +                        return Some(hir_id);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    None
 +}
 +
 +fn check_for_mutation<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    body: &Expr<'_>,
 +    bound_ids: &[Option<HirId>],
 +) -> (Option<Span>, Option<Span>) {
 +    let mut delegate = MutatePairDelegate {
 +        cx,
 +        hir_id_low: bound_ids[0],
 +        hir_id_high: bound_ids[1],
 +        span_low: None,
 +        span_high: None,
 +    };
 +    let def_id = body.hir_id.owner.to_def_id();
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        ExprUseVisitor::new(
 +            &mut delegate,
 +            &infcx,
 +            def_id.expect_local(),
 +            cx.param_env,
 +            cx.typeck_results(),
 +        )
 +        .walk_expr(body);
 +    });
 +    delegate.mutation_span()
 +}
 +
 +/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
 +fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
 +    match *pat {
 +        PatKind::Wild => true,
 +        PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => is_unused(&ident, body),
 +        _ => false,
 +    }
 +}
 +
 +struct LocalUsedVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    local: HirId,
 +    used: bool,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for LocalUsedVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if same_var(self.cx, expr, self.local) {
 +            self.used = true;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +struct VarVisitor<'a, 'tcx> {
 +    /// context reference
 +    cx: &'a LateContext<'tcx>,
 +    /// var name to look for as index
 +    var: HirId,
 +    /// indexed variables that are used mutably
 +    indexed_mut: FxHashSet<Symbol>,
 +    /// indirectly indexed variables (`v[(i + 4) % N]`), the extend is `None` for global
 +    indexed_indirectly: FxHashMap<Symbol, Option<region::Scope>>,
 +    /// subset of `indexed` of vars that are indexed directly: `v[i]`
 +    /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]`
 +    indexed_directly: FxHashMap<Symbol, (Option<region::Scope>, Ty<'tcx>)>,
 +    /// Any names that are used outside an index operation.
 +    /// Used to detect things like `&mut vec` used together with `vec[i]`
 +    referenced: FxHashSet<Symbol>,
 +    /// has the loop variable been used in expressions other than the index of
 +    /// an index op?
 +    nonindex: bool,
 +    /// Whether we are inside the `$` in `&mut $` or `$ = foo` or `$.bar`, where bar
 +    /// takes `&mut self`
 +    prefer_mutable: bool,
 +}
 +
 +impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
 +    fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
 +        if_chain! {
 +            // the indexed container is referenced by a name
 +            if let ExprKind::Path(ref seqpath) = seqexpr.kind;
 +            if let QPath::Resolved(None, ref seqvar) = *seqpath;
 +            if seqvar.segments.len() == 1;
 +            then {
 +                let index_used_directly = same_var(self.cx, idx, self.var);
 +                let indexed_indirectly = {
 +                    let mut used_visitor = LocalUsedVisitor {
 +                        cx: self.cx,
 +                        local: self.var,
 +                        used: false,
 +                    };
 +                    walk_expr(&mut used_visitor, idx);
 +                    used_visitor.used
 +                };
 +
 +                if indexed_indirectly || index_used_directly {
 +                    if self.prefer_mutable {
 +                        self.indexed_mut.insert(seqvar.segments[0].ident.name);
 +                    }
 +                    let res = qpath_res(self.cx, seqpath, seqexpr.hir_id);
 +                    match res {
 +                        Res::Local(hir_id) => {
 +                            let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
 +                            let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id);
 +                            let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id);
 +                            if indexed_indirectly {
 +                                self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
 +                            }
 +                            if index_used_directly {
 +                                self.indexed_directly.insert(
 +                                    seqvar.segments[0].ident.name,
 +                                    (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
 +                                );
 +                            }
 +                            return false;  // no need to walk further *on the variable*
 +                        }
 +                        Res::Def(DefKind::Static | DefKind::Const, ..) => {
 +                            if indexed_indirectly {
 +                                self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
 +                            }
 +                            if index_used_directly {
 +                                self.indexed_directly.insert(
 +                                    seqvar.segments[0].ident.name,
 +                                    (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
 +                                );
 +                            }
 +                            return false;  // no need to walk further *on the variable*
 +                        }
 +                        _ => (),
 +                    }
 +                }
 +            }
 +        }
 +        true
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            // a range index op
 +            if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind;
 +            if (meth.ident.name == sym!(index) && match_trait_method(self.cx, expr, &paths::INDEX))
 +                || (meth.ident.name == sym!(index_mut) && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
 +            if !self.check(&args[1], &args[0], expr);
 +            then { return }
 +        }
 +
 +        if_chain! {
 +            // an index op
 +            if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind;
 +            if !self.check(idx, seqexpr, expr);
 +            then { return }
 +        }
 +
 +        if_chain! {
 +            // directly using a variable
 +            if let ExprKind::Path(ref qpath) = expr.kind;
 +            if let QPath::Resolved(None, ref path) = *qpath;
 +            if path.segments.len() == 1;
 +            then {
 +                if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id) {
 +                    if local_id == self.var {
 +                        self.nonindex = true;
 +                    } else {
 +                        // not the correct variable, but still a variable
 +                        self.referenced.insert(path.segments[0].ident.name);
 +                    }
 +                }
 +            }
 +        }
 +
 +        let old = self.prefer_mutable;
 +        match expr.kind {
 +            ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs, _) => {
 +                self.prefer_mutable = true;
 +                self.visit_expr(lhs);
 +                self.prefer_mutable = false;
 +                self.visit_expr(rhs);
 +            },
 +            ExprKind::AddrOf(BorrowKind::Ref, mutbl, ref expr) => {
 +                if mutbl == Mutability::Mut {
 +                    self.prefer_mutable = true;
 +                }
 +                self.visit_expr(expr);
 +            },
 +            ExprKind::Call(ref f, args) => {
 +                self.visit_expr(f);
 +                for expr in args {
 +                    let ty = self.cx.typeck_results().expr_ty_adjusted(expr);
 +                    self.prefer_mutable = false;
 +                    if let ty::Ref(_, _, mutbl) = ty.kind {
 +                        if mutbl == Mutability::Mut {
 +                            self.prefer_mutable = true;
 +                        }
 +                    }
 +                    self.visit_expr(expr);
 +                }
 +            },
 +            ExprKind::MethodCall(_, _, args, _) => {
 +                let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +                for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
 +                    self.prefer_mutable = false;
 +                    if let ty::Ref(_, _, mutbl) = ty.kind {
 +                        if mutbl == Mutability::Mut {
 +                            self.prefer_mutable = true;
 +                        }
 +                    }
 +                    self.visit_expr(expr);
 +                }
 +            },
 +            ExprKind::Closure(_, _, body_id, ..) => {
 +                let body = self.cx.tcx.hir().body(body_id);
 +                self.visit_expr(&body.value);
 +            },
 +            _ => walk_expr(self, expr),
 +        }
 +        self.prefer_mutable = old;
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool {
 +    let def_id = match var_def_id(cx, expr) {
 +        Some(id) => id,
 +        None => return false,
 +    };
 +    if let Some(used_mutably) = mutated_variables(container, cx) {
 +        if used_mutably.contains(&def_id) {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool {
 +    let def_id = match var_def_id(cx, iter_expr) {
 +        Some(id) => id,
 +        None => return false,
 +    };
 +    let mut visitor = VarUsedAfterLoopVisitor {
 +        cx,
 +        def_id,
 +        iter_expr_id: iter_expr.hir_id,
 +        past_while_let: false,
 +        var_used_after_while_let: false,
 +    };
 +    if let Some(enclosing_block) = get_enclosing_block(cx, def_id) {
 +        walk_block(&mut visitor, enclosing_block);
 +    }
 +    visitor.var_used_after_while_let
 +}
 +
 +struct VarUsedAfterLoopVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    def_id: HirId,
 +    iter_expr_id: HirId,
 +    past_while_let: bool,
 +    var_used_after_while_let: bool,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.past_while_let {
 +            if Some(self.def_id) == var_def_id(self.cx, expr) {
 +                self.var_used_after_while_let = true;
 +            }
 +        } else if self.iter_expr_id == expr.hir_id {
 +            self.past_while_let = true;
 +        }
 +        walk_expr(self, expr);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Returns `true` if the type of expr is one that provides `IntoIterator` impls
 +/// for `&T` and `&mut T`, such as `Vec`.
 +#[rustfmt::skip]
 +fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    // no walk_ptrs_ty: calling iter() on a reference can make sense because it
 +    // will allow further borrows afterwards
 +    let ty = cx.typeck_results().expr_ty(e);
 +    is_iterable_array(ty, cx) ||
 +    is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
 +    match_type(cx, ty, &paths::LINKED_LIST) ||
 +    is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) ||
 +    is_type_diagnostic_item(cx, ty, sym!(hashset_type)) ||
 +    is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
 +    match_type(cx, ty, &paths::BINARY_HEAP) ||
 +    match_type(cx, ty, &paths::BTREEMAP) ||
 +    match_type(cx, ty, &paths::BTREESET)
 +}
 +
 +fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
 +    // IntoIterator is currently only implemented for array sizes <= 32 in rustc
 +    match ty.kind {
 +        ty::Array(_, n) => n
 +            .try_eval_usize(cx.tcx, cx.param_env)
 +            .map_or(false, |val| (0..=32).contains(&val)),
 +        _ => false,
 +    }
 +}
 +
 +/// If a block begins with a statement (possibly a `let` binding) and has an
 +/// expression, return it.
 +fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    if block.stmts.is_empty() {
 +        return None;
 +    }
 +    if let StmtKind::Local(ref local) = block.stmts[0].kind {
 +        local.init //.map(|expr| expr)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// If a block begins with an expression (with or without semicolon), return it.
 +fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    match block.expr {
 +        Some(ref expr) if block.stmts.is_empty() => Some(expr),
 +        None if !block.stmts.is_empty() => match block.stmts[0].kind {
 +            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => Some(expr),
 +            StmtKind::Local(..) | StmtKind::Item(..) => None,
 +        },
 +        _ => None,
 +    }
 +}
 +
 +/// Returns `true` if expr contains a single break expr without destination label
 +/// and
 +/// passed expression. The expression may be within a block.
 +fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
 +    match expr.kind {
 +        ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true,
 +        ExprKind::Block(ref b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)),
 +        _ => false,
 +    }
 +}
 +
 +// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
 +// incremented exactly once in the loop body, and initialized to zero
 +// at the start of the loop.
 +#[derive(Debug, PartialEq)]
 +enum VarState {
 +    Initial,  // Not examined yet
 +    IncrOnce, // Incremented exactly once, may be a loop counter
 +    Declared, // Declared but not (yet) initialized to zero
 +    Warn,
 +    DontWarn,
 +}
 +
 +/// Scan a for loop for variables that are incremented exactly once.
 +struct IncrementVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,          // context reference
 +    states: FxHashMap<HirId, VarState>, // incremented variables
 +    depth: u32,                         // depth of conditional expressions
 +    done: bool,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.done {
 +            return;
 +        }
 +
 +        // If node is a variable
 +        if let Some(def_id) = var_def_id(self.cx, expr) {
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                let state = self.states.entry(def_id).or_insert(VarState::Initial);
 +
 +                match parent.kind {
 +                    ExprKind::AssignOp(op, ref lhs, ref rhs) => {
 +                        if lhs.hir_id == expr.hir_id {
 +                            if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) {
 +                                *state = match *state {
 +                                    VarState::Initial if self.depth == 0 => VarState::IncrOnce,
 +                                    _ => VarState::DontWarn,
 +                                };
 +                            } else {
 +                                // Assigned some other value
 +                                *state = VarState::DontWarn;
 +                            }
 +                        }
 +                    },
 +                    ExprKind::Assign(ref lhs, _, _) if lhs.hir_id == expr.hir_id => *state = VarState::DontWarn,
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        *state = VarState::DontWarn
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        } else if is_loop(expr) || is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +            return;
 +        } else if let ExprKind::Continue(_) = expr.kind {
 +            self.done = true;
 +            return;
 +        }
 +        walk_expr(self, expr);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Checks whether a variable is initialized to zero at the start of a loop.
 +struct InitializeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,  // context reference
 +    end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here.
 +    var_id: HirId,
 +    state: VarState,
 +    name: Option<Symbol>,
 +    depth: u32, // depth of conditional expressions
 +    past_loop: bool,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        // Look for declarations of the variable
 +        if let StmtKind::Local(ref local) = stmt.kind {
 +            if local.pat.hir_id == self.var_id {
 +                if let PatKind::Binding(.., ident, _) = local.pat.kind {
 +                    self.name = Some(ident.name);
 +
 +                    self.state = local.init.as_ref().map_or(VarState::Declared, |init| {
 +                        if is_integer_const(&self.cx, init, 0) {
 +                            VarState::Warn
 +                        } else {
 +                            VarState::Declared
 +                        }
 +                    })
 +                }
 +            }
 +        }
 +        walk_stmt(self, stmt);
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.state == VarState::DontWarn {
 +            return;
 +        }
 +        if expr.hir_id == self.end_expr.hir_id {
 +            self.past_loop = true;
 +            return;
 +        }
 +        // No need to visit expressions before the variable is
 +        // declared
 +        if self.state == VarState::IncrOnce {
 +            return;
 +        }
 +
 +        // If node is the desired variable, see how it's used
 +        if var_def_id(self.cx, expr) == Some(self.var_id) {
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                match parent.kind {
 +                    ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = VarState::DontWarn;
 +                    },
 +                    ExprKind::Assign(ref lhs, ref rhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = if is_integer_const(&self.cx, rhs, 0) && self.depth == 0 {
 +                            VarState::Warn
 +                        } else {
 +                            VarState::DontWarn
 +                        }
 +                    },
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        self.state = VarState::DontWarn
 +                    },
 +                    _ => (),
 +                }
 +            }
 +
 +            if self.past_loop {
 +                self.state = VarState::DontWarn;
 +                return;
 +            }
 +        } else if !self.past_loop && is_loop(expr) {
 +            self.state = VarState::DontWarn;
 +            return;
 +        } else if is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +            return;
 +        }
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<HirId> {
 +    if let ExprKind::Path(ref qpath) = expr.kind {
 +        let path_res = qpath_res(cx, qpath, expr.hir_id);
 +        if let Res::Local(hir_id) = path_res {
 +            return Some(hir_id);
 +        }
 +    }
 +    None
 +}
 +
 +fn is_loop(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Loop(..))
 +}
 +
 +fn is_conditional(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Match(..))
 +}
 +
 +fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id);
 +        let parent_node = cx.tcx.hir().get_parent_node(loop_block.hir_id);
 +        if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find(parent_node);
 +        then {
 +            return is_loop_nested(cx, loop_expr, iter_expr)
 +        }
 +    }
 +    false
 +}
 +
 +fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
 +    let mut id = loop_expr.hir_id;
 +    let iter_name = if let Some(name) = path_name(iter_expr) {
 +        name
 +    } else {
 +        return true;
 +    };
 +    loop {
 +        let parent = cx.tcx.hir().get_parent_node(id);
 +        if parent == id {
 +            return false;
 +        }
 +        match cx.tcx.hir().find(parent) {
 +            Some(Node::Expr(expr)) => {
 +                if let ExprKind::Loop(..) = expr.kind {
 +                    return true;
 +                };
 +            },
 +            Some(Node::Block(block)) => {
 +                let mut block_visitor = LoopNestVisitor {
 +                    hir_id: id,
 +                    iterator: iter_name,
 +                    nesting: Unknown,
 +                };
 +                walk_block(&mut block_visitor, block);
 +                if block_visitor.nesting == RuledOut {
 +                    return false;
 +                }
 +            },
 +            Some(Node::Stmt(_)) => (),
 +            _ => {
 +                return false;
 +            },
 +        }
 +        id = parent;
 +    }
 +}
 +
 +#[derive(PartialEq, Eq)]
 +enum Nesting {
 +    Unknown,     // no nesting detected yet
 +    RuledOut,    // the iterator is initialized or assigned within scope
 +    LookFurther, // no nesting detected, no further walk required
 +}
 +
 +use self::Nesting::{LookFurther, RuledOut, Unknown};
 +
 +struct LoopNestVisitor {
 +    hir_id: HirId,
 +    iterator: Symbol,
 +    nesting: Nesting,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        if stmt.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +        } else if self.nesting == Unknown {
 +            walk_stmt(self, stmt);
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if expr.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +            return;
 +        }
 +        match expr.kind {
 +            ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => {
 +                if match_var(path, self.iterator) {
 +                    self.nesting = RuledOut;
 +                }
 +            },
 +            _ => walk_expr(self, expr),
 +        }
 +    }
 +
 +    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if let PatKind::Binding(.., span_name, _) = pat.kind {
 +            if self.iterator == span_name.name {
 +                self.nesting = RuledOut;
 +                return;
 +            }
 +        }
 +        walk_pat(self, pat)
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn path_name(e: &Expr<'_>) -> Option<Symbol> {
 +    if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind {
 +        let segments = &path.segments;
 +        if segments.len() == 1 {
 +            return Some(segments[0].ident.name);
 +        }
 +    };
 +    None
 +}
 +
 +fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
 +    if constant(cx, cx.typeck_results(), cond).is_some() {
 +        // A pure constant condition (e.g., `while false`) is not linted.
 +        return;
 +    }
 +
 +    let mut var_visitor = VarCollectorVisitor {
 +        cx,
 +        ids: FxHashSet::default(),
 +        def_ids: FxHashMap::default(),
 +        skip: false,
 +    };
 +    var_visitor.visit_expr(cond);
 +    if var_visitor.skip {
 +        return;
 +    }
 +    let used_in_condition = &var_visitor.ids;
 +    let no_cond_variable_mutated = if let Some(used_mutably) = mutated_variables(expr, cx) {
 +        used_in_condition.is_disjoint(&used_mutably)
 +    } else {
 +        return;
 +    };
 +    let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
 +
 +    let mut has_break_or_return_visitor = HasBreakOrReturnVisitor {
 +        has_break_or_return: false,
 +    };
 +    has_break_or_return_visitor.visit_expr(expr);
 +    let has_break_or_return = has_break_or_return_visitor.has_break_or_return;
 +
 +    if no_cond_variable_mutated && !mutable_static_in_cond {
 +        span_lint_and_then(
 +            cx,
 +            WHILE_IMMUTABLE_CONDITION,
 +            cond.span,
 +            "variables in the condition are not mutated in the loop body",
 +            |diag| {
 +                diag.note("this may lead to an infinite or to a never running loop");
 +
 +                if has_break_or_return {
 +                    diag.note("this loop contains `return`s or `break`s");
 +                    diag.help("rewrite it as `if cond { loop { } }`");
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +struct HasBreakOrReturnVisitor {
 +    has_break_or_return: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.has_break_or_return {
 +            return;
 +        }
 +
 +        match expr.kind {
 +            ExprKind::Ret(_) | ExprKind::Break(_, _) => {
 +                self.has_break_or_return = true;
 +                return;
 +            },
 +            _ => {},
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Collects the set of variables in an expression
 +/// Stops analysis if a function call is found
 +/// Note: In some cases such as `self`, there are no mutable annotation,
 +/// All variables definition IDs are collected
 +struct VarCollectorVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    ids: FxHashSet<HirId>,
 +    def_ids: FxHashMap<def_id::DefId, bool>,
 +    skip: bool,
 +}
 +
 +impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
 +    fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Path(ref qpath) = ex.kind;
 +            if let QPath::Resolved(None, _) = *qpath;
 +            let res = qpath_res(self.cx, qpath, ex.hir_id);
 +            then {
 +                match res {
 +                    Res::Local(hir_id) => {
 +                        self.ids.insert(hir_id);
 +                    },
 +                    Res::Def(DefKind::Static, def_id) => {
 +                        let mutable = self.cx.tcx.is_mutable_static(def_id);
 +                        self.def_ids.insert(def_id, mutable);
 +                    },
 +                    _ => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
 +        match ex.kind {
 +            ExprKind::Path(_) => self.insert_def_id(ex),
 +            // If there is any function/method call… we just stop analysis
 +            ExprKind::Call(..) | ExprKind::MethodCall(..) => self.skip = true,
 +
 +            _ => walk_expr(self, ex),
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
 +
 +fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 +    check_needless_collect_direct_usage(expr, cx);
 +    check_needless_collect_indirect_usage(expr, cx);
 +}
 +fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 +    if_chain! {
 +        if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
 +        if let ExprKind::MethodCall(ref chain_method, _, _, _) = args[0].kind;
 +        if chain_method.ident.name == sym!(collect) && match_trait_method(cx, &args[0], &paths::ITERATOR);
 +        if let Some(ref generic_args) = chain_method.args;
 +        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
 +        then {
 +            let ty = cx.typeck_results().node_type(ty.hir_id);
 +            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
 +                is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
 +                match_type(cx, ty, &paths::BTREEMAP) ||
 +                is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) {
 +                if method.ident.name == sym!(len) {
 +                    let span = shorten_needless_collect_span(expr);
 +                    span_lint_and_sugg(
 +                        cx,
 +                        NEEDLESS_COLLECT,
 +                        span,
 +                        NEEDLESS_COLLECT_MSG,
 +                        "replace with",
 +                        "count()".to_string(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +                if method.ident.name == sym!(is_empty) {
 +                    let span = shorten_needless_collect_span(expr);
 +                    span_lint_and_sugg(
 +                        cx,
 +                        NEEDLESS_COLLECT,
 +                        span,
 +                        NEEDLESS_COLLECT_MSG,
 +                        "replace with",
 +                        "next().is_none()".to_string(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +                if method.ident.name == sym!(contains) {
 +                    let contains_arg = snippet(cx, args[1].span, "??");
 +                    let span = shorten_needless_collect_span(expr);
 +                    span_lint_and_then(
 +                        cx,
 +                        NEEDLESS_COLLECT,
 +                        span,
 +                        NEEDLESS_COLLECT_MSG,
 +                        |diag| {
 +                            let (arg, pred) = if contains_arg.starts_with('&') {
 +                                ("x", &contains_arg[1..])
 +                            } else {
 +                                ("&x", &*contains_arg)
 +                            };
 +                            diag.span_suggestion(
 +                                span,
 +                                "replace with",
 +                                format!(
 +                                    "any(|{}| x == {})",
 +                                    arg, pred
 +                                ),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 +    if let ExprKind::Block(ref block, _) = expr.kind {
 +        for ref stmt in block.stmts {
 +            if_chain! {
 +                if let StmtKind::Local(
 +                    Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. },
 +                    init: Some(ref init_expr), .. }
 +                ) = stmt.kind;
 +                if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
 +                if method_name.ident.name == sym!(collect) && match_trait_method(cx, &init_expr, &paths::ITERATOR);
 +                if let Some(ref generic_args) = method_name.args;
 +                if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
 +                if let ty = cx.typeck_results().node_type(ty.hir_id);
 +                if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
 +                    is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
 +                    match_type(cx, ty, &paths::LINKED_LIST);
 +                if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
 +                if iter_calls.len() == 1;
 +                then {
 +                    // Suggest replacing iter_call with iter_replacement, and removing stmt
 +                    let iter_call = &iter_calls[0];
 +                    span_lint_and_then(
 +                        cx,
 +                        NEEDLESS_COLLECT,
 +                        stmt.span.until(iter_call.span),
 +                        NEEDLESS_COLLECT_MSG,
 +                        |diag| {
 +                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
 +                            diag.multipart_suggestion(
 +                                iter_call.get_suggestion_text(),
 +                                vec![
 +                                    (stmt.span, String::new()),
 +                                    (iter_call.span, iter_replacement)
 +                                ],
 +                                Applicability::MachineApplicable,// MaybeIncorrect,
 +                            ).emit();
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct IterFunction {
 +    func: IterFunctionKind,
 +    span: Span,
 +}
 +impl IterFunction {
 +    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
 +        match &self.func {
 +            IterFunctionKind::IntoIter => String::new(),
 +            IterFunctionKind::Len => String::from(".count()"),
 +            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
 +            IterFunctionKind::Contains(span) => format!(".any(|x| x == {})", snippet(cx, *span, "..")),
 +        }
 +    }
 +    fn get_suggestion_text(&self) -> &'static str {
 +        match &self.func {
 +            IterFunctionKind::IntoIter => {
 +                "Use the original Iterator instead of collecting it and then producing a new one"
 +            },
 +            IterFunctionKind::Len => {
 +                "Take the original Iterator's count instead of collecting it and finding the length"
 +            },
 +            IterFunctionKind::IsEmpty => {
 +                "Check if the original Iterator has anything instead of collecting it and seeing if it's empty"
 +            },
 +            IterFunctionKind::Contains(_) => {
 +                "Check if the original Iterator contains an element instead of collecting then checking"
 +            },
 +        }
 +    }
 +}
 +enum IterFunctionKind {
 +    IntoIter,
 +    Len,
 +    IsEmpty,
 +    Contains(Span),
 +}
 +
 +struct IterFunctionVisitor {
 +    uses: Vec<IterFunction>,
 +    seen_other: bool,
 +    target: Ident,
 +}
 +impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 +        // Check function calls on our collection
 +        if_chain! {
 +            if let ExprKind::MethodCall(method_name, _, ref args, _) = &expr.kind;
 +            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. }) = args.get(0);
 +            if let &[name] = &path.segments;
 +            if name.ident == self.target;
 +            then {
 +                let len = sym!(len);
 +                let is_empty = sym!(is_empty);
 +                let contains = sym!(contains);
 +                match method_name.ident.name {
 +                    sym::into_iter => self.uses.push(
 +                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
 +                    ),
 +                    name if name == len => self.uses.push(
 +                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
 +                    ),
 +                    name if name == is_empty => self.uses.push(
 +                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
 +                    ),
 +                    name if name == contains => self.uses.push(
 +                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
 +                    ),
 +                    _ => self.seen_other = true,
 +                }
 +                return
 +            }
 +        }
 +        // Check if the collection is used for anything else
 +        if_chain! {
 +            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, ref path)), .. } = expr;
 +            if let &[name] = &path.segments;
 +            if name.ident == self.target;
 +            then {
 +                self.seen_other = true;
 +            } else {
 +                walk_expr(self, expr);
 +            }
 +        }
 +    }
 +
 +    type Map = Map<'tcx>;
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Detect the occurences of calls to `iter` or `into_iter` for the
 +/// given identifier
 +fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
 +    let mut visitor = IterFunctionVisitor {
 +        uses: Vec::new(),
 +        target: identifier,
 +        seen_other: false,
 +    };
 +    visitor.visit_block(block);
 +    if visitor.seen_other {
 +        None
 +    } else {
 +        Some(visitor.uses)
 +    }
 +}
 +
 +fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span {
 +    if_chain! {
 +        if let ExprKind::MethodCall(.., args, _) = &expr.kind;
 +        if let ExprKind::MethodCall(_, span, ..) = &args[0].kind;
 +        then {
 +            return expr.span.with_lo(span.lo());
 +        }
 +    }
 +    unreachable!();
 +}
index 641e6a17043246937384a2ae7c946d44a91fc634,0000000000000000000000000000000000000000..1cd5b2012922f72ac65772a64de3af1f3d38c2e8
mode 100644,000000..100644
--- /dev/null
@@@ -1,150 -1,0 +1,150 @@@
-         "You are needlessly cloning iterator elements",
-         "Remove the `map` call",
 +use crate::utils::paths;
 +use crate::utils::{
 +    is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::mir::Mutability;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::Ident;
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
 +    /// `iterator.cloned()` instead
 +    ///
 +    /// **Why is this bad?** Readability, this can be written more concisely
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// let x = vec![42, 43];
 +    /// let y = x.iter();
 +    /// let z = y.map(|i| *i);
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// let x = vec![42, 43];
 +    /// let y = x.iter();
 +    /// let z = y.cloned();
 +    /// ```
 +    pub MAP_CLONE,
 +    style,
 +    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
 +}
 +
 +declare_lint_pass!(MapClone => [MAP_CLONE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MapClone {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
 +            if args.len() == 2;
 +            if method.ident.as_str() == "map";
 +            let ty = cx.typeck_results().expr_ty(&args[0]);
 +            if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
 +            if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
 +            let closure_body = cx.tcx.hir().body(body_id);
 +            let closure_expr = remove_blocks(&closure_body.value);
 +            then {
 +                match closure_body.params[0].pat.kind {
 +                    hir::PatKind::Ref(ref inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
 +                        hir::BindingAnnotation::Unannotated, .., name, None
 +                    ) = inner.kind {
 +                        if ident_eq(name, closure_expr) {
 +                            lint(cx, e.span, args[0].span, true);
 +                        }
 +                    },
 +                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
 +                        match closure_expr.kind {
 +                            hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
 +                                if ident_eq(name, inner) {
 +                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind {
 +                                        lint(cx, e.span, args[0].span, true);
 +                                    }
 +                                }
 +                            },
 +                            hir::ExprKind::MethodCall(ref method, _, ref obj, _) => {
 +                                if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
 +                                    && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
 +
 +                                    let obj_ty = cx.typeck_results().expr_ty(&obj[0]);
 +                                    if let ty::Ref(_, ty, _) = obj_ty.kind {
 +                                        let copy = is_copy(cx, ty);
 +                                        lint(cx, e.span, args[0].span, copy);
 +                                    } else {
 +                                        lint_needless_cloning(cx, e.span, args[0].span);
 +                                    }
 +                                }
 +                            },
 +                            _ => {},
 +                        }
 +                    },
 +                    _ => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
 +    if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.kind {
 +        path.segments.len() == 1 && path.segments[0].ident == name
 +    } else {
 +        false
 +    }
 +}
 +
 +fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
 +    span_lint_and_sugg(
 +        cx,
 +        MAP_CLONE,
 +        root.trim_start(receiver).unwrap(),
-             "You are using an explicit closure for copying elements",
-             "Consider calling the dedicated `copied` method",
++        "you are needlessly cloning iterator elements",
++        "remove the `map` call",
 +        String::new(),
 +        Applicability::MachineApplicable,
 +    )
 +}
 +
 +fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
 +    let mut applicability = Applicability::MachineApplicable;
 +    if copied {
 +        span_lint_and_sugg(
 +            cx,
 +            MAP_CLONE,
 +            replace,
-             "You are using an explicit closure for cloning elements",
-             "Consider calling the dedicated `cloned` method",
++            "you are using an explicit closure for copying elements",
++            "consider calling the dedicated `copied` method",
 +            format!(
 +                "{}.copied()",
 +                snippet_with_applicability(cx, root, "..", &mut applicability)
 +            ),
 +            applicability,
 +        )
 +    } else {
 +        span_lint_and_sugg(
 +            cx,
 +            MAP_CLONE,
 +            replace,
++            "you are using an explicit closure for cloning elements",
++            "consider calling the dedicated `cloned` method",
 +            format!(
 +                "{}.cloned()",
 +                snippet_with_applicability(cx, root, "..", &mut applicability)
 +            ),
 +            applicability,
 +        )
 +    }
 +}
index faa20687ef61f3c938e7853f9783ced3c97552af,0000000000000000000000000000000000000000..57966452253d52e75e55367ff540000448324377
mode 100644,000000..100644
--- /dev/null
@@@ -1,101 -1,0 +1,101 @@@
- use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
 +use crate::utils::walk_ptrs_ty;
++use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`.
 +    ///
 +    /// **Why is this bad?** This can panic at runtime.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust, no_run
 +    /// let arr = vec![0, 1, 2, 3];
 +    /// let idx = 1;
 +    ///
 +    /// // Bad
 +    /// match arr[idx] {
 +    ///     0 => println!("{}", 0),
 +    ///     1 => println!("{}", 3),
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust, no_run
 +    /// let arr = vec![0, 1, 2, 3];
 +    /// let idx = 1;
 +    ///
 +    /// // Good
 +    /// match arr.get(idx) {
 +    ///     Some(0) => println!("{}", 0),
 +    ///     Some(1) => println!("{}", 3),
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub MATCH_ON_VEC_ITEMS,
 +    pedantic,
 +    "matching on vector elements can panic"
 +}
 +
 +declare_lint_pass!(MatchOnVecItems => [MATCH_ON_VEC_ITEMS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), expr.span);
 +            if let ExprKind::Match(ref match_expr, _, MatchSource::Normal) = expr.kind;
 +            if let Some(idx_expr) = is_vec_indexing(cx, match_expr);
 +            if let ExprKind::Index(vec, idx) = idx_expr.kind;
 +
 +            then {
 +                // FIXME: could be improved to suggest surrounding every pattern with Some(_),
 +                // but only when `or_patterns` are stabilized.
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_ON_VEC_ITEMS,
 +                    match_expr.span,
 +                    "indexing into a vector may panic",
 +                    "try this",
 +                    format!(
 +                        "{}.get({})",
 +                        snippet(cx, vec.span, ".."),
 +                        snippet(cx, idx.span, "..")
 +                    ),
 +                    Applicability::MaybeIncorrect
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    if_chain! {
 +        if let ExprKind::Index(ref array, ref index) = expr.kind;
 +        if is_vector(cx, array);
 +        if !is_full_range(cx, index);
 +
 +        then {
 +            return Some(expr);
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let ty = cx.typeck_results().expr_ty(expr);
 +    let ty = walk_ptrs_ty(ty);
 +    is_type_diagnostic_item(cx, ty, sym!(vec_type))
 +}
 +
 +fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let ty = cx.typeck_results().expr_ty(expr);
 +    let ty = walk_ptrs_ty(ty);
 +    is_type_lang_item(cx, ty, LangItem::RangeFull)
 +}
index 2265a1888556af0ed9150af0ecb3e97c9a7f2f1b,0000000000000000000000000000000000000000..9996df69470f0e9242548fb8f41a1e93f93067a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,3650 -1,0 +1,3861 @@@
- use rustc_middle::ty::subst::GenericArgKind;
- use rustc_middle::ty::{self, Ty, TyS};
 +mod bind_instead_of_map;
 +mod inefficient_to_string;
 +mod manual_saturating_arithmetic;
 +mod option_map_unwrap_or;
 +mod unnecessary_filter_map;
++mod unnecessary_lazy_eval;
 +
 +use std::borrow::Cow;
 +use std::fmt;
 +use std::iter;
 +
 +use bind_instead_of_map::BindInsteadOfMap;
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{self, Visitor};
++use rustc_hir::{TraitItem, TraitItemKind};
 +use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
-     get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy,
-     is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment,
-     match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths,
-     remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
-     span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty,
-     walk_ptrs_ty_depth, SpanlessEq,
++use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{sym, SymbolStr};
 +
 +use crate::consts::{constant, Constant};
 +use crate::utils::usage::mutated_variables;
 +use crate::utils::{
-     /// # struct FooError;
++    contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
++    is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
++    last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
++    method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
++    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
++    span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
 +};
 +
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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");
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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::<(), ()>(())
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn add(&self, other: &X) -> X {
 +    ///         // ..
 +    /// # X
 +    ///     }
 +    /// }
 +    /// ```
 +    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 |`self` taken          |
 +    /// |-------|----------------------|
 +    /// |`as_`  |`&self` or `&mut self`|
 +    /// |`from_`| none                 |
 +    /// |`into_`|`self`                |
 +    /// |`is_`  |`&self` or none       |
 +    /// |`to_`  |`&self`               |
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # struct X;
 +    /// impl X {
 +    ///     fn as_str(self) -> &'static str {
 +    ///         // ..
 +    /// # ""
 +    ///     }
 +    /// }
 +    /// ```
 +    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:** This is the same as
 +    /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
 +    ///
 +    /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
 +    ///
 +    /// **Known problems:** Actually *renaming* the function may break clients if
 +    /// the function is part of the public interface. In that case, be mindful of
 +    /// the stability guarantees you've given your users.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # struct X;
 +    /// impl<'a> X {
 +    ///     pub fn as_str(self) -> &'a str {
 +    ///         "foo"
 +    ///     }
 +    /// }
 +    /// ```
 +    pub WRONG_PUB_SELF_CONVENTION,
 +    restriction,
 +    "defining a public 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?");
 +    /// ```
 +    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 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);
 +    /// ```
 +    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));
 +    /// ```
 +    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()`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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());
 +    /// ```
 +    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)`.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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 });
 +    /// ```
 +    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(_)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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(_)`,
 +    ///
 +    /// **Why is this bad?** Readability, this can be written more concisely as a
 +    /// single method call using `_.flat_map(_)`
 +    ///
 +    /// **Known problems:**
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let vec = vec![vec![1]];
 +    ///
 +    /// // Bad
 +    /// vec.iter().map(|x| x.iter()).flatten();
 +    ///
 +    /// // Good
 +    /// vec.iter().flat_map(|x| x.iter());
 +    /// ```
 +    pub MAP_FLATTEN,
 +    pedantic,
 +    "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(_)`,
 +    /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
 +    ///
 +    /// **Why is this bad?** Readability, this can be written more concisely as a
 +    /// single method call.
 +    ///
 +    /// **Known problems:** Often requires a condition + Option/Iterator creation
 +    /// inside the closure.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let vec = vec![1];
 +    ///
 +    /// // Bad
 +    /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2);
 +    ///
 +    /// // Good
 +    /// vec.iter().filter_map(|x| if *x == 0 {
 +    ///     Some(*x * 2)
 +    /// } else {
 +    ///     None
 +    /// });
 +    /// ```
 +    pub FILTER_MAP,
 +    pedantic,
 +    "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
 +}
 +
 +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 a
 +    /// single method call.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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 });
 +    /// ```
 +    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`.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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();
 +    /// ```
 +    pub FLAT_MAP_IDENTITY,
 +    complexity,
 +    "call to `flat_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `_.find(_).map(_)`.
 +    ///
 +    /// **Why is this bad?** Readability, this can be written more concisely as a
 +    /// single method call.
 +    ///
 +    /// **Known problems:** Often requires a condition + Option/Iterator creation
 +    /// inside the closure.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    ///  (0..3).find(|x| *x == 2).map(|x| x * 2);
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    ///  (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
 +    /// ```
 +    pub FIND_MAP,
 +    pedantic,
 +    "using a combination of `find` and `map` can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for an iterator search (such as `find()`,
 +    /// `position()`, or `rposition()`) followed by a call to `is_some()`.
 +    ///
 +    /// **Why is this bad?** Readability, this can be written more concisely as
 +    /// `_.any(_)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0).is_some();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().any(|x| *x == 0);
 +    /// ```
 +    pub SEARCH_IS_SOME,
 +    complexity,
 +    "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
 +}
 +
 +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(_)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.chars().next() == Some('_') {};
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.starts_with('_') {};
 +    /// ```
 +    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();
 +    /// ```
 +    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));
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// 42u64.clone();
 +    /// ```
 +    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);
 +    /// ```
 +    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`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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
 +    /// }
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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());
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
++    /// In an impl block:
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct NotAFoo;
 +    /// impl Foo {
 +    ///     fn new() -> NotAFoo {
 +    /// # NotAFoo
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
-     ///     // Good. Return type contains `Self`
-     ///     fn new() -> Result<Foo, FooError> {
-     ///         # Ok(Foo)
++    /// struct Bar(Foo);
 +    /// impl Foo {
-     /// struct Bar(Foo);
++    ///     // Bad. The type name must contain `Self`
++    ///     fn new() -> Bar {
++    /// # Bar(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
-     ///     // Bad. The type name must contain `Self`.
-     ///     fn new() -> Bar {
-     ///         # Bar(Foo)
++    /// # struct FooError;
 +    /// impl Foo {
-     /// Here `c_str` point to a freed address. The correct use would be:
++    ///     // 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;
++    /// }
++    /// ```
 +    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');
 +    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 getting the inner pointer of a temporary
 +    /// `CString`.
 +    ///
 +    /// **Why is this bad?** The inner pointer of a `CString` is only valid as long
 +    /// as the `CString` is alive.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::ffi::CString;
 +    /// # fn call_some_ffi_func(_: *const i8) {}
 +    /// #
 +    /// let c_str = CString::new("foo").unwrap().as_ptr();
 +    /// unsafe {
 +    ///     call_some_ffi_func(c_str);
 +    /// }
 +    /// ```
-             ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]),
++    /// Here `c_str` points to a freed address. The correct use would be:
 +    /// ```rust
 +    /// # use std::ffi::CString;
 +    /// # fn call_some_ffi_func(_: *const i8) {}
 +    /// #
 +    /// let c_str = CString::new("foo").unwrap();
 +    /// unsafe {
 +    ///     call_some_ffi_func(c_str.as_ptr());
 +    /// }
 +    /// ```
 +    pub TEMPORARY_CSTRING_AS_PTR,
 +    correctness,
 +    "getting the inner pointer of a temporary `CString`"
 +}
 +
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,should_panic
 +    /// for x in (0..100).step_by(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 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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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();
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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;
 +    /// ```
 +    pub GET_UNWRAP,
 +    restriction,
 +    "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
 +}
 +
 +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
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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();
 +    /// ```
 +    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(_)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let name = "_";
 +    ///
 +    /// // Bad
 +    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
 +    ///
 +    /// // Good
 +    /// name.ends_with('_') || name.ends_with('-');
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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);
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// let _ = (&vec![3, 4, 5]).into_iter();
 +    ///
 +    /// // Good
 +    /// let _ = (&vec![3, 4, 5]).iter();
 +    /// ```
 +    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. Or, if you intend to
 +    /// drive the iterator to completion, you can just use `for_each` instead.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// let _ = (0..3).map(|x| x + 2).count();
 +    /// ```
 +    pub SUSPICIOUS_MAP,
 +    complexity,
 +    "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()
 +    /// };
 +    /// ```
 +    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);
 +    /// ```
 +    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
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// unsafe { (&() as *const ()).offset(1) };
 +    /// ```
 +    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>(())
 +    /// # };
 +    /// ```
 +    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 a
 +    /// single method call.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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()
 +    /// # ;
 +    /// ```
 +    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()`
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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);
 +    /// ```
 +    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 with a single-character string literal,
++    /// and push with a char would work fine.
++    ///
++    /// **Why is this bad?** It's less clear that we are pushing a single character
++    ///
++    /// **Known problems:** None
++    ///
++    /// **Example:**
++    /// ```
++    /// let mut string = String::new();
++    /// string.push_str("R");
++    /// ```
++    /// Could be written as
++    /// ```
++    /// let mut string = String::new();
++    /// string.push('R');
++    /// ```
++    pub SINGLE_CHAR_PUSH_STR,
++    style,
++    "`push_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);
++    /// ```
++    pub UNNECESSARY_LAZY_EVALUATIONS,
++    style,
++    "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
++}
++
 +declare_lint_pass!(Methods => [
 +    UNWRAP_USED,
 +    EXPECT_USED,
 +    SHOULD_IMPLEMENT_TRAIT,
 +    WRONG_SELF_CONVENTION,
 +    WRONG_PUB_SELF_CONVENTION,
 +    OK_EXPECT,
 +    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,
 +    INEFFICIENT_TO_STRING,
 +    NEW_RET_NO_SELF,
 +    SINGLE_CHAR_PATTERN,
++    SINGLE_CHAR_PUSH_STR,
 +    SEARCH_IS_SOME,
 +    TEMPORARY_CSTRING_AS_PTR,
 +    FILTER_NEXT,
 +    SKIP_WHILE_NEXT,
 +    FILTER_MAP,
 +    FILTER_MAP_NEXT,
 +    FLAT_MAP_IDENTITY,
 +    FIND_MAP,
 +    MAP_FLATTEN,
 +    ITERATOR_STEP_BY_ZERO,
 +    ITER_NEXT_SLICE,
 +    ITER_NTH,
 +    ITER_NTH_ZERO,
 +    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,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Methods {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if in_macro(expr.span) {
 +            return;
 +        }
 +
 +        let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
 +        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();
 +
 +        match method_names.as_slice() {
 +            ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false),
 +            ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true),
 +            ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]),
 +            ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
 +            ["expect", ..] => lint_expect(cx, expr, arg_lists[0]),
 +            ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
-                 // check missing trait implementations
-                     for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS {
-                         if name == method_name &&
-                             sig.decl.inputs.len() == n_args &&
-                             out_type.matches(cx, &sig.decl.output) &&
-                             self_kind.matches(cx, self_ty, first_arg_ty) &&
-                             fn_header_equals(*fn_header, sig.header) {
-                             span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
-                                 "defining a method called `{}` on this type; consider implementing \
-                                 the `{}` trait or choosing a less ambiguous name", name, trait_name));
++            ["unwrap_or_else", "map"] => {
++                if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
++                    unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or");
++                }
++            },
 +            ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
 +            ["and_then", ..] => {
++                unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and");
 +                bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
 +                bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
 +            },
 +            ["or_else", ..] => {
++                unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
 +                bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
 +            },
 +            ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
 +            ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
 +            ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
 +            ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
 +            ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
 +            ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
 +            ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
 +            ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
 +            ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
 +            ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
 +            ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
 +            ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0], method_spans[1]),
 +            ["is_some", "position"] => {
 +                lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0], method_spans[1])
 +            },
 +            ["is_some", "rposition"] => {
 +                lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1])
 +            },
 +            ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
 +            ["as_ptr", "unwrap" | "expect"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]),
 +            ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
 +            ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
 +            ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
 +            ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
 +            ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),
 +            ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
 +            ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
 +            ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
 +            ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]),
 +            ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
 +            ["count", "map"] => lint_suspicious_map(cx, expr),
 +            ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr),
 +            ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
 +                manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..])
 +            },
 +            ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
 +                check_pointer_offset(cx, expr, arg_lists[0])
 +            },
 +            ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
 +            ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
 +            ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
++            ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"),
++            ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"),
++            ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"),
 +            _ => {},
 +        }
 +
 +        match expr.kind {
 +            hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => {
 +                lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
 +                lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
 +
 +                let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
 +                if args.len() == 1 && method_call.ident.name == sym!(clone) {
 +                    lint_clone_on_copy(cx, expr, &args[0], self_ty);
 +                    lint_clone_on_ref_ptr(cx, expr, &args[0]);
 +                }
 +                if args.len() == 1 && method_call.ident.name == sym!(to_string) {
 +                    inefficient_to_string::lint(cx, expr, &args[0], self_ty);
 +                }
 +
++                if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
++                    if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
++                        lint_single_char_push_string(cx, expr, args);
++                    }
++                }
++
 +                match self_ty.kind {
 +                    ty::Ref(_, ty, _) if ty.kind == ty::Str => {
 +                        for &(method, pos) in &PATTERN_METHODS {
 +                            if method_call.ident.name.as_str() == method && args.len() > pos {
 +                                lint_single_char_pattern(cx, expr, &args[pos]);
 +                            }
 +                        }
 +                    },
 +                    ty::Ref(..) if method_call.ident.name == sym!(into_iter) => {
 +                        lint_into_iter(cx, expr, self_ty, *method_span);
 +                    },
 +                    _ => (),
 +                }
 +            },
 +            hir::ExprKind::Binary(op, ref lhs, ref rhs)
 +                if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
 +            {
 +                let mut info = BinaryExprInfo {
 +                    expr,
 +                    chain: lhs,
 +                    other: rhs,
 +                    eq: op.node == hir::BinOpKind::Eq,
 +                };
 +                lint_binary_expr_with_method_call(cx, &mut info);
 +            }
 +            _ => (),
 +        }
 +    }
 +
++    #[allow(clippy::too_many_lines)]
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
 +        if in_external_macro(cx.sess(), impl_item.span) {
 +            return;
 +        }
 +        let name = impl_item.ident.name.as_str();
 +        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id);
 +        let item = cx.tcx.hir().expect_item(parent);
 +        let def_id = cx.tcx.hir().local_def_id(item.hir_id);
 +        let self_ty = cx.tcx.type_of(def_id);
 +        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();
 +            if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind;
 +
 +            let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
 +            let method_sig = cx.tcx.fn_sig(method_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 cx.access_levels.is_exported(impl_item.hir_id) {
-             let contains_self_ty = |ty: Ty<'tcx>| {
-                 ty.walk().any(|inner| match inner.unpack() {
-                     GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty),
-                     GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-                 })
-             };
++                    // 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(cx, &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 let Some((ref conv, self_kinds)) = &CONVENTIONS
 +                    .iter()
 +                    .find(|(ref conv, _)| conv.check(&name))
 +                {
 +                    if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
 +                        let lint = if item.vis.node.is_pub() {
 +                            WRONG_PUB_SELF_CONVENTION
 +                        } else {
 +                            WRONG_SELF_CONVENTION
 +                        };
 +
 +                        span_lint(
 +                            cx,
 +                            lint,
 +                            first_arg.pat.span,
 +                            &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name",
 +                                conv,
 +                                &self_kinds
 +                                    .iter()
 +                                    .map(|k| k.description())
 +                                    .collect::<Vec<_>>()
 +                                    .join(" or ")
 +                            ),
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +
++        // if this impl block implements a trait, lint in trait definition instead
++        if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
++            return;
++        }
++
 +        if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
 +            let ret_ty = return_ty(cx, impl_item.hir_id);
 +
-             if contains_self_ty(ret_ty) {
 +            // walk the return type and check for Self (this does not check associated types)
-                         if contains_self_ty(projection_predicate.ty) {
++            if contains_ty(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.predicates_of(def_id).predicates {
 +                    if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
 +                        // walk the associated type and check for Self
-             format!(
-                 "{}::<{}>::clone(&{})",
-                 caller_type,
-                 subst.type_at(0),
-                 snippet(cx, arg.span, "_")
-             ),
++                        if contains_ty(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_chain! {
++            if !in_external_macro(cx.tcx.sess, item.span);
++            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.hir_id.owner.to_def_id()).self_ty();
++            if !contains_ty(ret_ty, self_ty);
++
++            then {
++                span_lint(
++                    cx,
++                    NEW_RET_NO_SELF,
++                    item.span,
++                    "methods called `new` usually return `Self`",
++                );
++            }
++        }
++    }
 +}
 +
 +/// Checks for the `OR_FUN_CALL` lint.
 +#[allow(clippy::too_many_lines)]
 +fn lint_or_fun_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +    method_span: Span,
 +    name: &str,
 +    args: &'tcx [hir::Expr<'_>],
 +) {
 +    // Searches an expression for method calls or function calls that aren't ctors
 +    struct FunCallFinder<'a, 'tcx> {
 +        cx: &'a LateContext<'tcx>,
 +        found: bool,
 +    }
 +
 +    impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
 +        type Map = Map<'tcx>;
 +
 +        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +            let call_found = match &expr.kind {
 +                // ignore enum and struct constructors
 +                hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
 +                hir::ExprKind::MethodCall(..) => true,
 +                _ => false,
 +            };
 +
 +            if call_found {
 +                self.found |= true;
 +            }
 +
 +            if !self.found {
 +                intravisit::walk_expr(self, expr);
 +            }
 +        }
 +
 +        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +            intravisit::NestedVisitorMap::None
 +        }
 +    }
 +
 +    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
 +    fn check_unwrap_or_default(
 +        cx: &LateContext<'_>,
 +        name: &str,
 +        fun: &hir::Expr<'_>,
 +        self_expr: &hir::Expr<'_>,
 +        arg: &hir::Expr<'_>,
 +        or_has_args: bool,
 +        span: Span,
 +    ) -> bool {
 +        if_chain! {
 +            if !or_has_args;
 +            if name == "unwrap_or";
 +            if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +            let path = &*last_path_segment(qpath).ident.as_str();
 +            if ["default", "new"].contains(&path);
 +            let arg_ty = cx.typeck_results().expr_ty(arg);
 +            if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
 +            if implements_trait(cx, arg_ty, default_trait_id, &[]);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                span_lint_and_sugg(
 +                    cx,
 +                    OR_FUN_CALL,
 +                    span,
 +                    &format!("use of `{}` followed by a call to `{}`", name, path),
 +                    "try this",
 +                    format!(
 +                        "{}.unwrap_or_default()",
 +                        snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
 +                    ),
 +                    applicability,
 +                );
 +
 +                true
 +            } else {
 +                false
 +            }
 +        }
 +    }
 +
 +    /// Checks for `*or(foo())`.
 +    #[allow(clippy::too_many_arguments)]
 +    fn check_general_case<'tcx>(
 +        cx: &LateContext<'tcx>,
 +        name: &str,
 +        method_span: Span,
 +        fun_span: Span,
 +        self_expr: &hir::Expr<'_>,
 +        arg: &'tcx hir::Expr<'_>,
 +        or_has_args: bool,
 +        span: Span,
 +    ) {
 +        if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
 +            if path.ident.as_str() == "len" {
 +                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
 +
 +                match ty.kind {
 +                    ty::Slice(_) | ty::Array(_, _) => return,
 +                    _ => (),
 +                }
 +
 +                if match_type(cx, ty, &paths::VEC) {
 +                    return;
 +                }
 +            }
 +        }
 +
 +        // (path, fn_has_argument, methods, suffix)
 +        let know_types: &[(&[_], _, &[_], _)] = &[
 +            (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
 +            (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
 +        ];
 +
 +        if_chain! {
 +            if know_types.iter().any(|k| k.2.contains(&name));
 +
 +            let mut finder = FunCallFinder { cx: &cx, found: false };
 +            if { finder.visit_expr(&arg); finder.found };
 +            if !contains_return(&arg);
 +
 +            let self_ty = cx.typeck_results().expr_ty(self_expr);
 +
 +            if let Some(&(_, fn_has_arguments, poss, suffix)) =
 +                know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
 +
 +            if poss.contains(&name);
 +
 +            then {
 +                let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
 +                    (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
 +                    (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
 +                    (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
 +                };
 +                let span_replace_word = method_span.with_hi(span.hi());
 +                span_lint_and_sugg(
 +                    cx,
 +                    OR_FUN_CALL,
 +                    span_replace_word,
 +                    &format!("use of `{}` followed by a function call", name),
 +                    "try this",
 +                    format!("{}_{}({})", name, suffix, sugg),
 +                    Applicability::HasPlaceholders,
 +                );
 +            }
 +        }
 +    }
 +
 +    if args.len() == 2 {
 +        match args[1].kind {
 +            hir::ExprKind::Call(ref fun, ref or_args) => {
 +                let or_has_args = !or_args.is_empty();
 +                if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
 +                    check_general_case(
 +                        cx,
 +                        name,
 +                        method_span,
 +                        fun.span,
 +                        &args[0],
 +                        &args[1],
 +                        or_has_args,
 +                        expr.span,
 +                    );
 +                }
 +            },
 +            hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case(
 +                cx,
 +                name,
 +                method_span,
 +                span,
 +                &args[0],
 +                &args[1],
 +                !or_args.is_empty(),
 +                expr.span,
 +            ),
 +            _ => {},
 +        }
 +    }
 +}
 +
 +/// Checks for the `EXPECT_FUN_CALL` lint.
 +#[allow(clippy::too_many_lines)]
 +fn lint_expect_fun_call(
 +    cx: &LateContext<'_>,
 +    expr: &hir::Expr<'_>,
 +    method_span: Span,
 +    name: &str,
 +    args: &[hir::Expr<'_>],
 +) {
 +    // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
 +    // `&str`
 +    fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
 +        let mut arg_root = arg;
 +        loop {
 +            arg_root = match &arg_root.kind {
 +                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
 +                hir::ExprKind::MethodCall(method_name, _, call_args, _) => {
 +                    if call_args.len() == 1
 +                        && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
 +                        && {
 +                            let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
 +                            let base_type = walk_ptrs_ty(arg_type);
 +                            base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
 +                        }
 +                    {
 +                        &call_args[0]
 +                    } else {
 +                        break;
 +                    }
 +                },
 +                _ => break,
 +            };
 +        }
 +        arg_root
 +    }
 +
 +    // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
 +    // converted to string.
 +    fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
 +        let arg_ty = cx.typeck_results().expr_ty(arg);
 +        if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
 +            return false;
 +        }
 +        if let ty::Ref(_, ty, ..) = arg_ty.kind {
 +            if ty.kind == ty::Str && can_be_static_str(cx, arg) {
 +                return false;
 +            }
 +        };
 +        true
 +    }
 +
 +    // Check if an expression could have type `&'static str`, knowing that it
 +    // has type `&str` for some lifetime.
 +    fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
 +        match arg.kind {
 +            hir::ExprKind::Lit(_) => true,
 +            hir::ExprKind::Call(fun, _) => {
 +                if let hir::ExprKind::Path(ref p) = fun.kind {
 +                    match cx.qpath_res(p, fun.hir_id) {
 +                        hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
 +                            cx.tcx.fn_sig(def_id).output().skip_binder().kind,
 +                            ty::Ref(ty::ReStatic, ..)
 +                        ),
 +                        _ => false,
 +                    }
 +                } else {
 +                    false
 +                }
 +            },
 +            hir::ExprKind::MethodCall(..) => {
 +                cx.typeck_results()
 +                    .type_dependent_def_id(arg.hir_id)
 +                    .map_or(false, |method_id| {
 +                        matches!(
 +                            cx.tcx.fn_sig(method_id).output().skip_binder().kind,
 +                            ty::Ref(ty::ReStatic, ..)
 +                        )
 +                    })
 +            },
 +            hir::ExprKind::Path(ref p) => matches!(
 +                cx.qpath_res(p, arg.hir_id),
 +                hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _)
 +            ),
 +            _ => false,
 +        }
 +    }
 +
 +    fn generate_format_arg_snippet(
 +        cx: &LateContext<'_>,
 +        a: &hir::Expr<'_>,
 +        applicability: &mut Applicability,
 +    ) -> Vec<String> {
 +        if_chain! {
 +            if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref format_arg) = a.kind;
 +            if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.kind;
 +            if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.kind;
 +
 +            then {
 +                format_arg_expr_tup
 +                    .iter()
 +                    .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned())
 +                    .collect()
 +            } else {
 +                unreachable!()
 +            }
 +        }
 +    }
 +
 +    fn is_call(node: &hir::ExprKind<'_>) -> bool {
 +        match node {
 +            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => {
 +                is_call(&expr.kind)
 +            },
 +            hir::ExprKind::Call(..)
 +            | hir::ExprKind::MethodCall(..)
 +            // These variants are debatable or require further examination
 +            | hir::ExprKind::Match(..)
 +            | hir::ExprKind::Block{ .. } => true,
 +            _ => false,
 +        }
 +    }
 +
 +    if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
 +        return;
 +    }
 +
 +    let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
 +    let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
 +        "||"
 +    } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
 +        "|_|"
 +    } else {
 +        return;
 +    };
 +
 +    let arg_root = get_arg_root(cx, &args[1]);
 +
 +    let span_replace_word = method_span.with_hi(expr.span.hi());
 +
 +    let mut applicability = Applicability::MachineApplicable;
 +
 +    //Special handling for `format!` as arg_root
 +    if_chain! {
 +        if let hir::ExprKind::Block(block, None) = &arg_root.kind;
 +        if block.stmts.len() == 1;
 +        if let hir::StmtKind::Local(local) = &block.stmts[0].kind;
 +        if let Some(arg_root) = &local.init;
 +        if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.kind;
 +        if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1;
 +        if let hir::ExprKind::Call(_, format_args) = &inner_args[0].kind;
 +        then {
 +            let fmt_spec = &format_args[0];
 +            let fmt_args = &format_args[1];
 +
 +            let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()];
 +
 +            args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability));
 +
 +            let sugg = args.join(", ");
 +
 +            span_lint_and_sugg(
 +                cx,
 +                EXPECT_FUN_CALL,
 +                span_replace_word,
 +                &format!("use of `{}` followed by a function call", name),
 +                "try this",
 +                format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
 +                applicability,
 +            );
 +
 +            return;
 +        }
 +    }
 +
 +    let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
 +    if requires_to_string(cx, arg_root) {
 +        arg_root_snippet.to_mut().push_str(".to_string()");
 +    }
 +
 +    span_lint_and_sugg(
 +        cx,
 +        EXPECT_FUN_CALL,
 +        span_replace_word,
 +        &format!("use of `{}` followed by a function call", name),
 +        "try this",
 +        format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet),
 +        applicability,
 +    );
 +}
 +
 +/// Checks for the `CLONE_ON_COPY` lint.
 +fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
 +    let ty = cx.typeck_results().expr_ty(expr);
 +    if let ty::Ref(_, inner, _) = arg_ty.kind {
 +        if let ty::Ref(_, innermost, _) = inner.kind {
 +            span_lint_and_then(
 +                cx,
 +                CLONE_DOUBLE_REF,
 +                expr.span,
 +                "using `clone` on a double-reference; \
 +                this will copy the reference instead of cloning the inner type",
 +                |diag| {
 +                    if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
 +                        let mut ty = innermost;
 +                        let mut n = 0;
 +                        while let ty::Ref(_, inner, _) = ty.kind {
 +                            ty = inner;
 +                            n += 1;
 +                        }
 +                        let refs: String = iter::repeat('&').take(n + 1).collect();
 +                        let derefs: String = iter::repeat('*').take(n).collect();
 +                        let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "try dereferencing it",
 +                            format!("{}({}{}).clone()", refs, derefs, snip.deref()),
 +                            Applicability::MaybeIncorrect,
 +                        );
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "or try being explicit if you are sure, that you want to clone a reference",
 +                            explicit,
 +                            Applicability::MaybeIncorrect,
 +                        );
 +                    }
 +                },
 +            );
 +            return; // don't report clone_on_copy
 +        }
 +    }
 +
 +    if is_copy(cx, ty) {
 +        let snip;
 +        if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
 +            let parent = cx.tcx.hir().get_parent_node(expr.hir_id);
 +            match &cx.tcx.hir().get(parent) {
 +                hir::Node::Expr(parent) => match parent.kind {
 +                    // &*x is a nop, &x.clone() is not
 +                    hir::ExprKind::AddrOf(..) => return,
 +                    // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
 +                    hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
 +                        return;
 +                    },
 +
 +                    _ => {},
 +                },
 +                hir::Node::Stmt(stmt) => {
 +                    if let hir::StmtKind::Local(ref loc) = stmt.kind {
 +                        if let hir::PatKind::Ref(..) = loc.pat.kind {
 +                            // let ref y = *x borrows x, let ref y = x.clone() does not
 +                            return;
 +                        }
 +                    }
 +                },
 +                _ => {},
 +            }
 +
 +            // x.clone() might have dereferenced x, possibly through Deref impls
 +            if cx.typeck_results().expr_ty(arg) == ty {
 +                snip = Some(("try removing the `clone` call", format!("{}", snippet)));
 +            } else {
 +                let deref_count = cx
 +                    .typeck_results()
 +                    .expr_adjustments(arg)
 +                    .iter()
 +                    .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
 +                    .count();
 +                let derefs: String = iter::repeat('*').take(deref_count).collect();
 +                snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
 +            }
 +        } else {
 +            snip = None;
 +        }
 +        span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
 +            if let Some((text, snip)) = snip {
 +                diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
 +            }
 +        });
 +    }
 +}
 +
 +fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
 +    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
 +
 +    if let ty::Adt(_, subst) = obj_ty.kind {
 +        let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
 +            "Rc"
 +        } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
 +            "Arc"
 +        } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
 +            "Weak"
 +        } else {
 +            return;
 +        };
 +
++        let snippet = snippet_with_macro_callsite(cx, arg.span, "_");
++
 +        span_lint_and_sugg(
 +            cx,
 +            CLONE_ON_REF_PTR,
 +            expr.span,
 +            "using `.clone()` on a ref-counted pointer",
 +            "try this",
-                     "Using `.iter().next()` on a Slice without end index.",
++            format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet),
 +            Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
 +        );
 +    }
 +}
 +
 +fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
 +    let arg = &args[1];
 +    if let Some(arglists) = method_chain_args(arg, &["chars"]) {
 +        let target = &arglists[0][0];
 +        let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
 +        let ref_str = if self_ty.kind == ty::Str {
 +            ""
 +        } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
 +            "&"
 +        } else {
 +            return;
 +        };
 +
 +        let mut applicability = Applicability::MachineApplicable;
 +        span_lint_and_sugg(
 +            cx,
 +            STRING_EXTEND_CHARS,
 +            expr.span,
 +            "calling `.extend(_.chars())`",
 +            "try this",
 +            format!(
 +                "{}.push_str({}{})",
 +                snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
 +                ref_str,
 +                snippet_with_applicability(cx, target.span, "_", &mut applicability)
 +            ),
 +            applicability,
 +        );
 +    }
 +}
 +
 +fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
 +    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
 +    if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
 +        lint_string_extend(cx, expr, args);
 +    }
 +}
 +
 +fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
 +    if_chain! {
 +        let source_type = cx.typeck_results().expr_ty(source);
 +        if let ty::Adt(def, substs) = source_type.kind;
 +        if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
 +        if match_type(cx, substs.type_at(0), &paths::CSTRING);
 +        then {
 +            span_lint_and_then(
 +                cx,
 +                TEMPORARY_CSTRING_AS_PTR,
 +                expr.span,
 +                "you are getting the inner pointer of a temporary `CString`",
 +                |diag| {
 +                    diag.note("that pointer will be invalid outside this expression");
 +                    diag.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
 +                });
 +        }
 +    }
 +}
 +
 +fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
 +    if_chain! {
 +        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type));
 +        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
 +        if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 +
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                ITER_CLONED_COLLECT,
 +                to_replace,
 +                "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
 +                more readable",
 +                "try",
 +                ".to_vec()".to_string(),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
 +    fn check_fold_with_op(
 +        cx: &LateContext<'_>,
 +        expr: &hir::Expr<'_>,
 +        fold_args: &[hir::Expr<'_>],
 +        fold_span: Span,
 +        op: hir::BinOpKind,
 +        replacement_method_name: &str,
 +        replacement_has_args: bool,
 +    ) {
 +        if_chain! {
 +            // Extract the body of the closure passed to fold
 +            if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind;
 +            let closure_body = cx.tcx.hir().body(body_id);
 +            let closure_expr = remove_blocks(&closure_body.value);
 +
 +            // Check if the closure body is of the form `acc <op> some_expr(x)`
 +            if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.kind;
 +            if bin_op.node == op;
 +
 +            // Extract the names of the two arguments to the closure
 +            if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat);
 +            if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat);
 +
 +            if match_var(&*left_expr, first_arg_ident);
 +            if replacement_has_args || match_var(&*right_expr, second_arg_ident);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let sugg = if replacement_has_args {
 +                    format!(
 +                        "{replacement}(|{s}| {r})",
 +                        replacement = replacement_method_name,
 +                        s = second_arg_ident,
 +                        r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
 +                    )
 +                } else {
 +                    format!(
 +                        "{replacement}()",
 +                        replacement = replacement_method_name,
 +                    )
 +                };
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    UNNECESSARY_FOLD,
 +                    fold_span.with_hi(expr.span.hi()),
 +                    // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
 +                    "this `.fold` can be written more succinctly using another method",
 +                    "try",
 +                    sugg,
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    // Check that this is a call to Iterator::fold rather than just some function called fold
 +    if !match_trait_method(cx, expr, &paths::ITERATOR) {
 +        return;
 +    }
 +
 +    assert!(
 +        fold_args.len() == 3,
 +        "Expected fold_args to have three entries - the receiver, the initial value and the closure"
 +    );
 +
 +    // Check if the first argument to .fold is a suitable literal
 +    if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind {
 +        match lit.node {
 +            ast::LitKind::Bool(false) => {
 +                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
 +            },
 +            ast::LitKind::Bool(true) => {
 +                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
 +            },
 +            ast::LitKind::Int(0, _) => {
 +                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
 +            },
 +            ast::LitKind::Int(1, _) => {
 +                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
 +            },
 +            _ => (),
 +        }
 +    }
 +}
 +
 +fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
 +            span_lint(
 +                cx,
 +                ITERATOR_STEP_BY_ZERO,
 +                expr.span,
 +                "Iterator::step_by(0) will panic at runtime",
 +            );
 +        }
 +    }
 +}
 +
 +fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
 +    let caller_expr = &iter_args[0];
 +
 +    // Skip lint if the `iter().next()` expression is a for loop argument,
 +    // since it is already covered by `&loops::ITER_NEXT_LOOP`
 +    let mut parent_expr_opt = get_parent_expr(cx, expr);
 +    while let Some(parent_expr) = parent_expr_opt {
 +        if higher::for_loop(parent_expr).is_some() {
 +            return;
 +        }
 +        parent_expr_opt = get_parent_expr(cx, parent_expr);
 +    }
 +
 +    if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
 +        // caller is a Slice
 +        if_chain! {
 +            if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
 +            if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
 +                = higher::range(index_expr);
 +            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
 +            if let ast::LitKind::Int(start_idx, _) = start_lit.node;
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                span_lint_and_sugg(
 +                    cx,
 +                    ITER_NEXT_SLICE,
 +                    expr.span,
-             "Using `.iter().next()` on an array",
++                    "using `.iter().next()` on a Slice without end index",
 +                    "try calling",
 +                    format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
 +                    applicability,
 +                );
 +            }
 +        }
 +    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
 +        || matches!(
 +            &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind,
 +            ty::Array(_, _)
 +        )
 +    {
 +        // caller is a Vec or an Array
 +        let mut applicability = Applicability::MachineApplicable;
 +        span_lint_and_sugg(
 +            cx,
 +            ITER_NEXT_SLICE,
 +            expr.span,
- ) {
++            "using `.iter().next()` on an array",
 +            "try calling",
 +            format!(
 +                "{}.get(0)",
 +                snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
 +            ),
 +            applicability,
 +        );
 +    }
 +}
 +
 +fn lint_iter_nth<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +    nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]],
 +    is_mut: bool,
 +) {
 +    let iter_args = nth_and_iter_args[1];
 +    let mut_str = if is_mut { "_mut" } else { "" };
 +    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
 +        "slice"
 +    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) {
 +        "Vec"
 +    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
 +        "VecDeque"
 +    } else {
 +        let nth_args = nth_and_iter_args[0];
 +        lint_iter_nth_zero(cx, expr, &nth_args);
 +        return; // caller is not a type that we want to lint
 +    };
 +
 +    span_lint_and_help(
 +        cx,
 +        ITER_NTH,
 +        expr.span,
 +        &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type),
 +        None,
 +        &format!("calling `.get{}()` is both faster and more readable", mut_str),
 +    );
 +}
 +
 +fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
 +    if_chain! {
 +        if match_trait_method(cx, expr, &paths::ITERATOR);
 +        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
 +        then {
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                ITER_NTH_ZERO,
 +                expr.span,
 +                "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
 +                "try calling `.next()` instead of `.nth(0)`",
 +                format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
 +    // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
 +    // because they do not implement `IndexMut`
 +    let mut applicability = Applicability::MachineApplicable;
 +    let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
 +    let get_args_str = if get_args.len() > 1 {
 +        snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
 +    } else {
 +        return; // not linting on a .get().unwrap() chain or variant
 +    };
 +    let mut needs_ref;
 +    let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
 +        needs_ref = get_args_str.parse::<usize>().is_ok();
 +        "slice"
 +    } else if is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) {
 +        needs_ref = get_args_str.parse::<usize>().is_ok();
 +        "Vec"
 +    } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) {
 +        needs_ref = get_args_str.parse::<usize>().is_ok();
 +        "VecDeque"
 +    } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym!(hashmap_type)) {
 +        needs_ref = true;
 +        "HashMap"
 +    } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
 +        needs_ref = true;
 +        "BTreeMap"
 +    } else {
 +        return; // caller is not a type that we want to lint
 +    };
 +
 +    let mut span = expr.span;
 +
 +    // Handle the case where the result is immediately dereferenced
 +    // by not requiring ref and pulling the dereference into the
 +    // suggestion.
 +    if_chain! {
 +        if needs_ref;
 +        if let Some(parent) = get_parent_expr(cx, expr);
 +        if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.kind;
 +        then {
 +            needs_ref = false;
 +            span = parent.span;
 +        }
 +    }
 +
 +    let mut_str = if is_mut { "_mut" } else { "" };
 +    let borrow_str = if !needs_ref {
 +        ""
 +    } else if is_mut {
 +        "&mut "
 +    } else {
 +        "&"
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        GET_UNWRAP,
 +        span,
 +        &format!(
 +            "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
 +            mut_str, caller_type
 +        ),
 +        "try this",
 +        format!(
 +            "{}{}[{}]",
 +            borrow_str,
 +            snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
 +            get_args_str
 +        ),
 +        applicability,
 +    );
 +}
 +
 +fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
 +    // lint if caller of skip is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        if let [caller, n] = skip_args {
 +            let hint = format!(".nth({})", snippet(cx, n.span, ".."));
 +            span_lint_and_sugg(
 +                cx,
 +                ITER_SKIP_NEXT,
 +                expr.span.trim_start(caller.span).unwrap(),
 +                "called `skip(x).next()` on an iterator",
 +                "use `nth` instead",
 +                hint,
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +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_type)),
 +            ty::Array(_, size) => size
 +                .try_eval_usize(cx.tcx, cx.param_env)
 +                .map_or(false, |size| size < 32),
 +            ty::Ref(_, inner, _) => may_slice(cx, inner),
 +            _ => false,
 +        }
 +    }
 +
 +    if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
 +        if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
 +            Some(&args[0])
 +        } 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,
 +        }
 +    }
 +}
 +
 +/// lint use of `unwrap()` for `Option`s and `Result`s
 +fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
 +    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0]));
 +
 +    let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
 +        Some((UNWRAP_USED, "an Option", "None"))
 +    } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
 +        Some((UNWRAP_USED, "a Result", "Err"))
 +    } else {
 +        None
 +    };
 +
 +    if let Some((lint, kind, none_value)) = mess {
 +        span_lint_and_help(
 +            cx,
 +            lint,
 +            expr.span,
 +            &format!("used `unwrap()` on `{}` value", kind,),
 +            None,
 +            &format!(
 +                "if you don't want to handle the `{}` case gracefully, consider \
 +                using `expect()` to provide a better panic message",
 +                none_value,
 +            ),
 +        );
 +    }
 +}
 +
 +/// lint use of `expect()` for `Option`s and `Result`s
 +fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
 +    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0]));
 +
 +    let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
 +        Some((EXPECT_USED, "an Option", "None"))
 +    } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
 +        Some((EXPECT_USED, "a Result", "Err"))
 +    } else {
 +        None
 +    };
 +
 +    if let Some((lint, kind, none_value)) = mess {
 +        span_lint_and_help(
 +            cx,
 +            lint,
 +            expr.span,
 +            &format!("used `expect()` on `{}` value", kind,),
 +            None,
 +            &format!("if this value is an `{}`, it will panic", none_value,),
 +        );
 +    }
 +}
 +
 +/// lint use of `ok().expect()` for `Result`s
 +fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
 +    if_chain! {
 +        // lint if the caller of `ok()` is a `Result`
 +        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type));
 +        let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
 +        if let Some(error_type) = get_error_type(cx, result_type);
 +        if has_debug_impl(error_type, cx);
 +
 +        then {
 +            span_lint_and_help(
 +                cx,
 +                OK_EXPECT,
 +                expr.span,
 +                "called `ok().expect()` on a `Result` value",
 +                None,
 +                "you can call `expect()` directly on the `Result`",
 +            );
 +        }
 +    }
 +}
 +
 +/// lint use of `map().flatten()` for `Iterators` and 'Options'
 +fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
 +    // lint if caller of `.map().flatten()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
 +        let is_map_to_option = match map_closure_ty.kind {
 +            ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
 +                let map_closure_sig = match map_closure_ty.kind {
 +                    ty::Closure(_, substs) => substs.as_closure().sig(),
 +                    _ => map_closure_ty.fn_sig(cx.tcx),
 +                };
 +                let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output());
 +                is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type))
 +            },
 +            _ => false,
 +        };
 +
 +        let method_to_use = if is_map_to_option {
 +            // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
 +            "filter_map"
 +        } else {
 +            // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
 +            "flat_map"
 +        };
 +        let func_snippet = snippet(cx, map_args[1].span, "..");
 +        let hint = format!(".{0}({1})", method_to_use, func_snippet);
 +        span_lint_and_sugg(
 +            cx,
 +            MAP_FLATTEN,
 +            expr.span.with_lo(map_args[0].span.hi()),
 +            "called `map(..).flatten()` on an `Iterator`",
 +            &format!("try using `{}` instead", method_to_use),
 +            hint,
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +
 +    // lint if caller of `.map().flatten()` is an Option
 +    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
 +        let func_snippet = snippet(cx, map_args[1].span, "..");
 +        let hint = format!(".and_then({})", func_snippet);
 +        span_lint_and_sugg(
 +            cx,
 +            MAP_FLATTEN,
 +            expr.span.with_lo(map_args[0].span.hi()),
 +            "called `map(..).flatten()` on an `Option`",
 +            "try using `and_then` instead",
 +            hint,
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
++/// Return true if lint triggered
 +fn lint_map_unwrap_or_else<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    map_args: &'tcx [hir::Expr<'_>],
 +    unwrap_args: &'tcx [hir::Expr<'_>],
-                 return;
++) -> bool {
 +    // lint if the caller of `map()` is an `Option`
 +    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type));
 +    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type));
 +
 +    if is_option || is_result {
 +        // Don't make a suggestion that may fail to compile due to mutably borrowing
 +        // the same variable twice.
 +        let map_mutated_vars = mutated_variables(&map_args[0], cx);
 +        let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
 +        if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
 +            if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
-             return;
++                return false;
 +            }
 +        } else {
-         };
++            return false;
 +        }
 +
 +        // lint message
 +        let msg = if is_option {
 +            "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \
 +            `map_or_else(g, f)` instead"
 +        } else {
 +            "called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling \
 +            `.map_or_else(g, f)` instead"
 +        };
 +        // get snippets for args to map() and unwrap_or_else()
 +        let map_snippet = snippet(cx, map_args[1].span, "..");
 +        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
 +        // lint, with note if neither arg is > 1 line and both map() and
 +        // unwrap_or_else() have the same span
 +        let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
 +        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
 +        if same_span && !multiline {
 +            span_lint_and_note(
 +                cx,
 +                MAP_UNWRAP_OR,
 +                expr.span,
 +                msg,
 +                None,
 +                &format!(
 +                    "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`",
 +                    map_snippet, unwrap_snippet,
 +                ),
 +            );
++            return true;
 +        } else if same_span && multiline {
 +            span_lint(cx, MAP_UNWRAP_OR, expr.span, msg);
- /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
- fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
++            return true;
++        }
 +    }
++
++    false
 +}
 +
 +/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
 +fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
 +    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type));
 +    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type));
 +
 +    // There are two variants of this `map_or` lint:
 +    // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
 +    // (2) using `map_or` as a combinator instead of `and_then`
 +    //
 +    // (For this lint) we don't care if any other type calls `map_or`
 +    if !is_option && !is_result {
 +        return;
 +    }
 +
 +    let (lint_name, msg, instead, hint) = {
 +        let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
 +            match_qpath(qpath, &paths::OPTION_NONE)
 +        } else {
 +            return;
 +        };
 +
 +        if !default_arg_is_none {
 +            // nothing to lint!
 +            return;
 +        }
 +
 +        let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
 +            match_qpath(qpath, &paths::OPTION_SOME)
 +        } else {
 +            false
 +        };
 +
 +        if is_option {
 +            let self_snippet = snippet(cx, map_or_args[0].span, "..");
 +            let func_snippet = snippet(cx, map_or_args[2].span, "..");
 +            let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
 +                       `and_then(f)` instead";
 +            (
 +                OPTION_MAP_OR_NONE,
 +                msg,
 +                "try using `and_then` instead",
 +                format!("{0}.and_then({1})", self_snippet, func_snippet),
 +            )
 +        } else if f_arg_is_some {
 +            let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
 +                       `ok()` instead";
 +            let self_snippet = snippet(cx, map_or_args[0].span, "..");
 +            (
 +                RESULT_MAP_OR_INTO_OPTION,
 +                msg,
 +                "try using `ok` instead",
 +                format!("{0}.ok()", self_snippet),
 +            )
 +        } else {
 +            // nothing to lint!
 +            return;
 +        }
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        lint_name,
 +        expr.span,
 +        msg,
 +        instead,
 +        hint,
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +/// lint use of `filter().next()` for `Iterators`
 +fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
 +    // lint if caller of `.filter().next()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
 +                   `.find(p)` instead.";
 +        let filter_snippet = snippet(cx, filter_args[1].span, "..");
 +        if filter_snippet.lines().count() <= 1 {
 +            // add note if not multi-line
 +            span_lint_and_note(
 +                cx,
 +                FILTER_NEXT,
 +                expr.span,
 +                msg,
 +                None,
 +                &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
 +            );
 +        } else {
 +            span_lint(cx, FILTER_NEXT, expr.span, msg);
 +        }
 +    }
 +}
 +
 +/// lint use of `skip_while().next()` for `Iterators`
 +fn lint_skip_while_next<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _skip_while_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.skip_while().next()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        span_lint_and_help(
 +            cx,
 +            SKIP_WHILE_NEXT,
 +            expr.span,
 +            "called `skip_while(p).next()` on an `Iterator`",
 +            None,
 +            "this is more succinctly expressed by calling `.find(!p)` instead",
 +        );
 +    }
 +}
 +
 +/// lint use of `filter().map()` for `Iterators`
 +fn lint_filter_map<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _filter_args: &'tcx [hir::Expr<'_>],
 +    _map_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.filter().map()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter(p).map(q)` on an `Iterator`";
 +        let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
 +        span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
 +    }
 +}
 +
 +/// lint use of `filter_map().next()` for `Iterators`
 +fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
 +                   `.find_map(p)` instead.";
 +        let filter_snippet = snippet(cx, filter_args[1].span, "..");
 +        if filter_snippet.lines().count() <= 1 {
 +            span_lint_and_note(
 +                cx,
 +                FILTER_MAP_NEXT,
 +                expr.span,
 +                msg,
 +                None,
 +                &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
 +            );
 +        } else {
 +            span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
 +        }
 +    }
 +}
 +
 +/// lint use of `find().map()` for `Iterators`
 +fn lint_find_map<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _find_args: &'tcx [hir::Expr<'_>],
 +    map_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.filter().map()` is an Iterator
 +    if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
 +        let msg = "called `find(p).map(q)` on an `Iterator`";
 +        let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
 +        span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
 +    }
 +}
 +
 +/// lint use of `filter_map().map()` for `Iterators`
 +fn lint_filter_map_map<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _filter_args: &'tcx [hir::Expr<'_>],
 +    _map_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.filter().map()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter_map(p).map(q)` on an `Iterator`";
 +        let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
 +        span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
 +    }
 +}
 +
 +/// lint use of `filter().flat_map()` for `Iterators`
 +fn lint_filter_flat_map<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _filter_args: &'tcx [hir::Expr<'_>],
 +    _map_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.filter().flat_map()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter(p).flat_map(q)` on an `Iterator`";
 +        let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
 +                    and filtering by returning `iter::empty()`";
 +        span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
 +    }
 +}
 +
 +/// lint use of `filter_map().flat_map()` for `Iterators`
 +fn lint_filter_map_flat_map<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    _filter_args: &'tcx [hir::Expr<'_>],
 +    _map_args: &'tcx [hir::Expr<'_>],
 +) {
 +    // lint if caller of `.filter_map().flat_map()` is an Iterator
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`";
 +        let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
 +                    and filtering by returning `iter::empty()`";
 +        span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
 +    }
 +}
 +
 +/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
 +fn lint_flat_map_identity<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    flat_map_args: &'tcx [hir::Expr<'_>],
 +    flat_map_span: Span,
 +) {
 +    if match_trait_method(cx, expr, &paths::ITERATOR) {
 +        let arg_node = &flat_map_args[1].kind;
 +
 +        let apply_lint = |message: &str| {
 +            span_lint_and_sugg(
 +                cx,
 +                FLAT_MAP_IDENTITY,
 +                flat_map_span.with_hi(expr.span.hi()),
 +                message,
 +                "try",
 +                "flatten()".to_string(),
 +                Applicability::MachineApplicable,
 +            );
 +        };
 +
 +        if_chain! {
 +            if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
 +            let body = cx.tcx.hir().body(*body_id);
 +
 +            if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
 +            if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.kind;
 +
 +            if path.segments.len() == 1;
 +            if path.segments[0].ident.as_str() == binding_ident.as_str();
 +
 +            then {
 +                apply_lint("called `flat_map(|x| x)` on an `Iterator`");
 +            }
 +        }
 +
 +        if_chain! {
 +            if let hir::ExprKind::Path(ref qpath) = arg_node;
 +
 +            if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
 +
 +            then {
 +                apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
 +            }
 +        }
 +    }
 +}
 +
 +/// lint searching an Iterator followed by `is_some()`
 +fn lint_search_is_some<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    search_method: &str,
 +    search_args: &'tcx [hir::Expr<'_>],
 +    is_some_args: &'tcx [hir::Expr<'_>],
 +    method_span: Span,
 +) {
 +    // lint if caller of search is an Iterator
 +    if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
 +        let msg = format!(
 +            "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
 +             expressed by calling `any()`.",
 +            search_method
 +        );
 +        let search_snippet = snippet(cx, search_args[1].span, "..");
 +        if search_snippet.lines().count() <= 1 {
 +            // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
 +            // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
 +            let any_search_snippet = if_chain! {
 +                if search_method == "find";
 +                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind;
 +                let closure_body = cx.tcx.hir().body(body_id);
 +                if let Some(closure_arg) = closure_body.params.get(0);
 +                then {
 +                    if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
 +                        Some(search_snippet.replacen('&', "", 1))
 +                    } else if let Some(name) = get_arg_name(&closure_arg.pat) {
 +                        Some(search_snippet.replace(&format!("*{}", name), &name.as_str()))
 +                    } else {
 +                        None
 +                    }
 +                } else {
 +                    None
 +                }
 +            };
 +            // add note if not multi-line
 +            span_lint_and_sugg(
 +                cx,
 +                SEARCH_IS_SOME,
 +                method_span.with_hi(expr.span.hi()),
 +                &msg,
 +                "try this",
 +                format!(
 +                    "any({})",
 +                    any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
 +                ),
 +                Applicability::MachineApplicable,
 +            );
 +        } else {
 +            span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
 +        }
 +    }
 +}
 +
 +/// 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:ident, $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!(lint_chars_next_cmp, cx, info);
 +    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
 +    lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
 +    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
 +}
 +
 +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 +fn lint_chars_cmp(
 +    cx: &LateContext<'_>,
 +    info: &BinaryExprInfo<'_>,
 +    chain_methods: &[&str],
 +    lint: &'static Lint,
 +    suggest: &str,
 +) -> bool {
 +    if_chain! {
 +        if let Some(args) = method_chain_args(info.chain, chain_methods);
 +        if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.kind;
 +        if arg_char.len() == 1;
 +        if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(segment) = single_segment_path(qpath);
 +        if segment.ident.name == sym!(Some);
 +        then {
 +            let mut applicability = Applicability::MachineApplicable;
 +            let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
 +
 +            if self_ty.kind != ty::Str {
 +                return false;
 +            }
 +
 +            span_lint_and_sugg(
 +                cx,
 +                lint,
 +                info.expr.span,
 +                &format!("you should use the `{}` method", suggest),
 +                "like this",
 +                format!("{}{}.{}({})",
 +                        if info.eq { "" } else { "!" },
 +                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
 +                        suggest,
 +                        snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
 +                applicability,
 +            );
 +
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
 +
 +/// Checks for the `CHARS_NEXT_CMP` lint.
 +fn lint_chars_next_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 +    lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
 +}
 +
 +/// Checks for the `CHARS_LAST_CMP` lint.
 +fn lint_chars_last_cmp<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 +    if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
 +        true
 +    } else {
 +        lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
 +    }
 +}
 +
 +/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
 +fn lint_chars_cmp_with_unwrap<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    info: &BinaryExprInfo<'_>,
 +    chain_methods: &[&str],
 +    lint: &'static Lint,
 +    suggest: &str,
 +) -> bool {
 +    if_chain! {
 +        if let Some(args) = method_chain_args(info.chain, chain_methods);
 +        if let hir::ExprKind::Lit(ref lit) = info.other.kind;
 +        if let ast::LitKind::Char(c) = lit.node;
 +        then {
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                lint,
 +                info.expr.span,
 +                &format!("you should use the `{}` method", suggest),
 +                "like this",
 +                format!("{}{}.{}('{}')",
 +                        if info.eq { "" } else { "!" },
 +                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
 +                        suggest,
 +                        c),
 +                applicability,
 +            );
 +
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
 +fn lint_chars_next_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 +    lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
 +}
 +
 +/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
 +fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryExprInfo<'_>) -> bool {
 +    if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
 +        true
 +    } else {
 +        lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
 +    }
 +}
 +
-         if r.as_str().len() == 1;
++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 mut applicability = Applicability::MachineApplicable;
-             let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
++        let string = r.as_str();
++        if string.len() == 1;
 +        then {
-             span_lint_and_sugg(
-                 cx,
-                 SINGLE_CHAR_PATTERN,
-                 arg.span,
-                 "single-character string constant used as pattern",
-                 "try using a `char` instead",
-                 hint,
-                 applicability,
-             );
++            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!("'{}'", if ch == "'" { "\\'" } else { ch });
-         hir::ExprKind::Path(ref expr_qpath) => deref_aliases.iter().any(|path| match_qpath(expr_qpath, path)),
++            Some(hint)
++        } else {
++            None
 +        }
 +    }
 +}
 +
++/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
++fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
++    let mut applicability = Applicability::MachineApplicable;
++    if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
++        span_lint_and_sugg(
++            cx,
++            SINGLE_CHAR_PATTERN,
++            arg.span,
++            "single-character string constant used as pattern",
++            "try using a `char` instead",
++            hint,
++            applicability,
++        );
++    }
++}
++
++/// lint for length-1 `str`s as argument for `push_str`
++fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
++    let mut applicability = Applicability::MachineApplicable;
++    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
++        let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
++        let sugg = format!("{}.push({})", base_string_snippet, extension_string);
++        span_lint_and_sugg(
++            cx,
++            SINGLE_CHAR_PUSH_STR,
++            expr.span,
++            "calling `push_str()` using a single-character string literal",
++            "consider using `push` with a character literal",
++            sugg,
++            applicability,
++        );
++    }
++}
++
 +/// Checks for the `USELESS_ASREF` lint.
 +fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
 +    // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
 +    // check if the call is to the actual `AsRef` or `AsMut` trait
 +    if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
 +        // check if the type after `as_ref` or `as_mut` is the same as before
 +        let recvr = &as_ref_args[0];
 +        let rcv_ty = cx.typeck_results().expr_ty(recvr);
 +        let res_ty = cx.typeck_results().expr_ty(expr);
 +        let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
 +        let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
 +        if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
 +            // allow the `as_ref` or `as_mut` if it is followed by another method call
 +            if_chain! {
 +                if let Some(parent) = get_parent_expr(cx, expr);
 +                if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind;
 +                if span != &expr.span;
 +                then {
 +                    return;
 +                }
 +            }
 +
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                USELESS_ASREF,
 +                expr.span,
 +                &format!("this call to `{}` does nothing", call_name),
 +                "try this",
 +                snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> {
 +    has_iter_method(cx, self_ref_ty).map(|ty_name| {
 +        let mutbl = match self_ref_ty.kind {
 +            ty::Ref(_, _, mutbl) => mutbl,
 +            _ => unreachable!(),
 +        };
 +        let method_name = match mutbl {
 +            hir::Mutability::Not => "iter",
 +            hir::Mutability::Mut => "iter_mut",
 +        };
 +        (ty_name, method_name)
 +    })
 +}
 +
 +fn lint_into_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, self_ref_ty: Ty<'_>, method_span: Span) {
 +    if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) {
 +        return;
 +    }
 +    if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
 +        span_lint_and_sugg(
 +            cx,
 +            INTO_ITER_ON_REF,
 +            method_span,
 +            &format!(
 +                "this `.into_iter()` call is equivalent to `.{}()` and will not move the `{}`",
 +                method_name, kind,
 +            ),
 +            "call directly",
 +            method_name.to_string(),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
 +fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) {
 +    if_chain! {
 +        if let hir::ExprKind::Call(ref callee, ref args) = expr.kind;
 +        if args.is_empty();
 +        if let hir::ExprKind::Path(ref path) = callee.kind;
 +        if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
 +        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
 +        then {
 +            span_lint(
 +                cx,
 +                UNINIT_ASSUMED_INIT,
 +                outer.span,
 +                "this call for this type may be undefined behavior"
 +            );
 +        }
 +    }
 +}
 +
 +fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 +    match ty.kind {
 +        ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
 +        ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
 +        ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
 +        _ => false,
 +    }
 +}
 +
 +fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
 +    span_lint_and_help(
 +        cx,
 +        SUSPICIOUS_MAP,
 +        expr.span,
 +        "this call to `map()` won't have an effect on the call to `count()`",
 +        None,
 +        "make sure you did not confuse `map` with `filter` or `for_each`",
 +    );
 +}
 +
 +/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
 +fn lint_option_as_ref_deref<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +    as_ref_args: &[hir::Expr<'_>],
 +    map_args: &[hir::Expr<'_>],
 +    is_mut: bool,
 +) {
 +    let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 +
 +    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
 +    if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
 +        return;
 +    }
 +
 +    let deref_aliases: [&[&str]; 9] = [
 +        &paths::DEREF_TRAIT_METHOD,
 +        &paths::DEREF_MUT_TRAIT_METHOD,
 +        &paths::CSTRING_AS_C_STR,
 +        &paths::OS_STRING_AS_OS_STR,
 +        &paths::PATH_BUF_AS_PATH,
 +        &paths::STRING_AS_STR,
 +        &paths::STRING_AS_MUT_STR,
 +        &paths::VEC_AS_SLICE,
 +        &paths::VEC_AS_MUT_SLICE,
 +    ];
 +
 +    let is_deref = match map_args[1].kind {
- const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [
-     ("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"),
-     ("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
-     ("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
-     ("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
-     ("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
-     ("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
-     ("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
-     ("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
-     ("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
-     ("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
-     ("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"),
-     ("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
-     ("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
-     ("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"),
-     ("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
-     ("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
-     ("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
-     ("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"),
-     ("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
-     ("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
-     ("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
-     ("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
-     ("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"),
-     ("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"),
-     ("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
-     ("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"),
-     ("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"),
-     ("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"),
-     ("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"),
-     ("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"),
++        hir::ExprKind::Path(ref expr_qpath) => cx
++            .qpath_res(expr_qpath, map_args[1].hir_id)
++            .opt_def_id()
++            .map_or(false, |fun_def_id| {
++                deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
++            }),
 +        hir::ExprKind::Closure(_, _, body_id, _, _) => {
 +            let closure_body = cx.tcx.hir().body(body_id);
 +            let closure_expr = remove_blocks(&closure_body.value);
 +
 +            match &closure_expr.kind {
 +                hir::ExprKind::MethodCall(_, _, args, _) => {
 +                    if_chain! {
 +                        if args.len() == 1;
 +                        if let hir::ExprKind::Path(qpath) = &args[0].kind;
 +                        if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id);
 +                        if closure_body.params[0].pat.hir_id == local_id;
 +                        let adj = cx
 +                            .typeck_results()
 +                            .expr_adjustments(&args[0])
 +                            .iter()
 +                            .map(|x| &x.kind)
 +                            .collect::<Box<[_]>>();
 +                        if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
 +                        then {
 +                            let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
 +                            deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
 +                        } else {
 +                            false
 +                        }
 +                    }
 +                },
 +                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
 +                    if_chain! {
 +                        if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
 +                        if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
 +                        if let hir::ExprKind::Path(ref qpath) = inner2.kind;
 +                        if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id);
 +                        then {
 +                            closure_body.params[0].pat.hir_id == local_id
 +                        } else {
 +                            false
 +                        }
 +                    }
 +                },
 +                _ => false,
 +            }
 +        },
 +        _ => false,
 +    };
 +
 +    if is_deref {
 +        let current_method = if is_mut {
 +            format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
 +        } else {
 +            format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
 +        };
 +        let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
 +        let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
 +        let suggestion = format!("try using {} instead", method_hint);
 +
 +        let msg = format!(
 +            "called `{0}` on an Option value. This can be done more directly \
 +            by calling `{1}` instead",
 +            current_method, hint
 +        );
 +        span_lint_and_sugg(
 +            cx,
 +            OPTION_AS_REF_DEREF,
 +            expr.span,
 +            &msg,
 +            &suggestion,
 +            hint,
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
 +
 +/// Given a `Result<T, E>` type, return its error type (`E`).
 +fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
 +    match ty.kind {
 +        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
 +        _ => None,
 +    }
 +}
 +
 +/// This checks whether a given type is known to implement Debug.
 +fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
 +    cx.tcx
 +        .get_diagnostic_item(sym::debug_trait)
 +        .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
 +}
 +
 +enum Convention {
 +    Eq(&'static str),
 +    StartsWith(&'static str),
 +}
 +
 +#[rustfmt::skip]
 +const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
 +    (Convention::Eq("new"), &[SelfKind::No]),
 +    (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
 +    (Convention::StartsWith("from_"), &[SelfKind::No]),
 +    (Convention::StartsWith("into_"), &[SelfKind::Value]),
 +    (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
 +    (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
 +    (Convention::StartsWith("to_"), &[SelfKind::Ref]),
 +];
 +
 +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),
 +];
 +
 +#[rustfmt::skip]
 +const PATTERN_METHODS: [(&str, usize); 17] = [
 +    ("contains", 1),
 +    ("starts_with", 1),
 +    ("ends_with", 1),
 +    ("find", 1),
 +    ("rfind", 1),
 +    ("split", 1),
 +    ("rsplit", 1),
 +    ("split_terminator", 1),
 +    ("rsplit_terminator", 1),
 +    ("splitn", 2),
 +    ("rsplitn", 2),
 +    ("matches", 1),
 +    ("rmatches", 1),
 +    ("match_indices", 1),
 +    ("rmatch_indices", 1),
 +    ("trim_start_matches", 1),
 +    ("trim_end_matches", 1),
 +];
 +
 +#[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",
 +        }
 +    }
 +}
 +
 +impl Convention {
 +    #[must_use]
 +    fn check(&self, other: &str) -> bool {
 +        match *self {
 +            Self::Eq(this) => this == other,
 +            Self::StartsWith(this) => other.starts_with(this) && this != other,
 +        }
 +    }
 +}
 +
 +impl fmt::Display for Convention {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 +        match *self {
 +            Self::Eq(this) => this.fmt(f),
 +            Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OutType {
 +    Unit,
 +    Bool,
 +    Any,
 +    Ref,
 +}
 +
 +impl OutType {
 +    fn matches(self, cx: &LateContext<'_>, ty: &hir::FnRetTy<'_>) -> bool {
 +        let is_unit = |ty: &hir::Ty<'_>| SpanlessEq::new(cx).eq_ty_kind(&ty.kind, &hir::TyKind::Tup(&[]));
 +        match (self, ty) {
 +            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
 +            (Self::Unit, &hir::FnRetTy::Return(ref ty)) if is_unit(ty) => true,
 +            (Self::Bool, &hir::FnRetTy::Return(ref ty)) if is_bool(ty) => true,
 +            (Self::Any, &hir::FnRetTy::Return(ref ty)) if !is_unit(ty) => true,
 +            (Self::Ref, &hir::FnRetTy::Return(ref ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn is_bool(ty: &hir::Ty<'_>) -> bool {
 +    if let hir::TyKind::Path(ref p) = ty.kind {
 +        match_qpath(p, &["bool"])
 +    } else {
 +        false
 +    }
 +}
 +
 +// Returns `true` if `expr` contains a return expression
 +fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    struct RetCallFinder {
 +        found: bool,
 +    }
 +
 +    impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder {
 +        type Map = Map<'tcx>;
 +
 +        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +            if self.found {
 +                return;
 +            }
 +            if let hir::ExprKind::Ret(..) = &expr.kind {
 +                self.found = true;
 +            } else {
 +                intravisit::walk_expr(self, expr);
 +            }
 +        }
 +
 +        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +            intravisit::NestedVisitorMap::None
 +        }
 +    }
 +
 +    let mut visitor = RetCallFinder { found: false };
 +    visitor.visit_expr(expr);
 +    visitor.found
 +}
 +
 +fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
 +    if_chain! {
 +        if args.len() == 2;
 +        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind;
 +        if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
 +        if layout.is_zst();
 +        then {
 +            span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
 +        }
 +    }
 +}
 +
 +fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
 +    let ty = cx.typeck_results().expr_ty(&args[0]);
 +
 +    if !match_type(cx, ty, &paths::FILE_TYPE) {
 +        return;
 +    }
 +
 +    let span: Span;
 +    let verb: &str;
 +    let lint_unary: &str;
 +    let help_unary: &str;
 +    if_chain! {
 +        if let Some(parent) = get_parent_expr(cx, expr);
 +        if let hir::ExprKind::Unary(op, _) = parent.kind;
 +        if op == hir::UnOp::UnNot;
 +        then {
 +            lint_unary = "!";
 +            verb = "denies";
 +            help_unary = "";
 +            span = parent.span;
 +        } else {
 +            lint_unary = "";
 +            verb = "covers";
 +            help_unary = "!";
 +            span = expr.span;
 +        }
 +    }
 +    let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
 +    let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
 +    span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
 +}
 +
 +fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
 +    expected.constness == actual.constness
 +        && expected.unsafety == actual.unsafety
 +        && expected.asyncness == actual.asyncness
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..31517659c34dcbc9efa957fa7ba3c6f06603d1af
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,111 @@@
++use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg};
++use if_chain::if_chain;
++use rustc_errors::Applicability;
++use rustc_hir as hir;
++use rustc_lint::LateContext;
++
++use super::UNNECESSARY_LAZY_EVALUATIONS;
++
++// Return true if the expression is an accessor of any of the arguments
++fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool {
++    params.iter().any(|arg| {
++        if_chain! {
++            if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind;
++            if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind;
++            if let [p, ..] = path.segments;
++            then {
++                ident.name == p.ident.name
++            } else {
++                false
++            }
++        }
++    })
++}
++
++fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool {
++    paths.iter().any(|candidate| match_qpath(path, candidate))
++}
++
++fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool {
++    match expr.kind {
++        // Closures returning literals can be unconditionally simplified
++        hir::ExprKind::Lit(_) => true,
++
++        hir::ExprKind::Index(ref object, ref index) => {
++            // arguments are not being indexed into
++            if expr_uses_argument(object, params) {
++                false
++            } else {
++                // arguments are not used as index
++                !expr_uses_argument(index, params)
++            }
++        },
++
++        // Reading fields can be simplified if the object is not an argument of the closure
++        hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params),
++
++        // Paths can be simplified if the root is not the argument, this also covers None
++        hir::ExprKind::Path(_) => !expr_uses_argument(expr, params),
++
++        // Calls to Some, Ok, Err can be considered literals if they don't derive an argument
++        hir::ExprKind::Call(ref func, ref args) => if_chain! {
++            if variant_calls; // Disable lint when rules conflict with bind_instead_of_map
++            if let hir::ExprKind::Path(ref path) = func.kind;
++            if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]);
++            then {
++                // Recursively check all arguments
++                args.iter().all(|arg| can_simplify(arg, params, variant_calls))
++            } else {
++                false
++            }
++        },
++
++        // For anything more complex than the above, a closure is probably the right solution,
++        // or the case is handled by an other lint
++        _ => false,
++    }
++}
++
++/// lint use of `<fn>_else(simple closure)` for `Option`s and `Result`s that can be
++/// replaced with `<fn>(return value of simple closure)`
++pub(super) fn lint<'tcx>(
++    cx: &LateContext<'tcx>,
++    expr: &'tcx hir::Expr<'_>,
++    args: &'tcx [hir::Expr<'_>],
++    allow_variant_calls: bool,
++    simplify_using: &str,
++) {
++    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
++    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type));
++
++    if is_option || is_result {
++        if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
++            let body = cx.tcx.hir().body(eid);
++            let ex = &body.value;
++            let params = &body.params;
++
++            if can_simplify(ex, params, allow_variant_calls) {
++                let msg = if is_option {
++                    "unnecessary closure used to substitute value for `Option::None`"
++                } else {
++                    "unnecessary closure used to substitute value for `Result::Err`"
++                };
++
++                span_lint_and_sugg(
++                    cx,
++                    UNNECESSARY_LAZY_EVALUATIONS,
++                    expr.span,
++                    msg,
++                    &format!("Use `{}` instead", simplify_using),
++                    format!(
++                        "{0}.{1}({2})",
++                        snippet(cx, args[0].span, ".."),
++                        simplify_using,
++                        snippet(cx, ex.span, ".."),
++                    ),
++                    Applicability::MachineApplicable,
++                );
++            }
++        }
++    }
++}
index 482a563572db270fa63a436879cb4348a3a3f79f,0000000000000000000000000000000000000000..06f367a8b775f99ee7ae9fc610cc315c1170c4e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,740 -1,0 +1,739 @@@
-             ExprKind::Path(hir::QPath::LangItem(..)) => None,
-             ExprKind::Path(ref qpath) => {
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::FnKind;
 +use rustc_hir::{
 +    self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
 +    StmtKind, TyKind, UnOp,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::hygiene::DesugaringKind;
 +use rustc_span::source_map::{ExpnKind, Span};
 +
 +use crate::consts::{constant, Constant};
 +use crate::utils::sugg::Sugg;
 +use crate::utils::{
 +    get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats,
 +    last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg,
 +    span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq,
 +};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for function arguments and let bindings denoted as
 +    /// `ref`.
 +    ///
 +    /// **Why is this bad?** The `ref` declaration makes the function take an owned
 +    /// value, but turns the argument into a reference (which means that the value
 +    /// is destroyed when exiting the function). This adds not much value: either
 +    /// take a reference type, or take an owned value and create references in the
 +    /// body.
 +    ///
 +    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
 +    /// type of `x` is more obvious with the former.
 +    ///
 +    /// **Known problems:** If the argument is dereferenced within the function,
 +    /// removing the `ref` will lead to errors. This can be fixed by removing the
 +    /// dereferences, e.g., changing `*x` to `x` within the function.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// fn foo(ref x: u8) -> bool {
 +    ///     true
 +    /// }
 +    ///
 +    /// // Good
 +    /// fn foo(x: &u8) -> bool {
 +    ///     true
 +    /// }
 +    /// ```
 +    pub TOPLEVEL_REF_ARG,
 +    style,
 +    "an entire binding declared as `ref`, in a function argument or a `let` statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for comparisons to NaN.
 +    ///
 +    /// **Why is this bad?** NaN does not compare meaningfully to anything – not
 +    /// even itself – so those comparisons are simply wrong.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = 1.0;
 +    ///
 +    /// // Bad
 +    /// if x == f32::NAN { }
 +    ///
 +    /// // Good
 +    /// if x.is_nan() { }
 +    /// ```
 +    pub CMP_NAN,
 +    correctness,
 +    "comparisons to `NAN`, which will always return false, probably not intended"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for (in-)equality comparisons on floating-point
 +    /// values (apart from zero), except in functions called `*eq*` (which probably
 +    /// implement equality for a type involving floats).
 +    ///
 +    /// **Why is this bad?** Floating point calculations are usually imprecise, so
 +    /// asking if two values are *exactly* equal is asking for trouble. For a good
 +    /// guide on what to do, see [the floating point
 +    /// guide](http://www.floating-point-gui.de/errors/comparison).
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = 1.2331f64;
 +    /// let y = 1.2332f64;
 +    ///
 +    /// // Bad
 +    /// if y == 1.23f64 { }
 +    /// if y != x {} // where both are floats
 +    ///
 +    /// // Good
 +    /// let error = f64::EPSILON; // Use an epsilon for comparison
 +    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
 +    /// // let error = std::f64::EPSILON;
 +    /// if (y - 1.23f64).abs() < error { }
 +    /// if (y - x).abs() > error { }
 +    /// ```
 +    pub FLOAT_CMP,
 +    correctness,
 +    "using `==` or `!=` on float values instead of comparing difference with an epsilon"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for conversions to owned values just for the sake
 +    /// of a comparison.
 +    ///
 +    /// **Why is this bad?** The comparison can operate on a reference, so creating
 +    /// an owned value effectively throws it away directly afterwards, which is
 +    /// needlessly consuming code and heap space.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = "foo";
 +    /// # let y = String::from("foo");
 +    /// if x.to_owned() == y {}
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let x = "foo";
 +    /// # let y = String::from("foo");
 +    /// if x == y {}
 +    /// ```
 +    pub CMP_OWNED,
 +    perf,
 +    "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for getting the remainder of a division by one.
 +    ///
 +    /// **Why is this bad?** The result can only ever be zero. No one will write
 +    /// such code deliberately, unless trying to win an Underhanded Rust
 +    /// Contest. Even for that contest, it's probably a bad idea. Use something more
 +    /// underhanded.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let x = 1;
 +    /// let a = x % 1;
 +    /// ```
 +    pub MODULO_ONE,
 +    correctness,
 +    "taking a number modulo 1, which always returns 0"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for the use of bindings with a single leading
 +    /// underscore.
 +    ///
 +    /// **Why is this bad?** A single leading underscore is usually used to indicate
 +    /// that a binding will not be used. Using such a binding breaks this
 +    /// expectation.
 +    ///
 +    /// **Known problems:** The lint does not work properly with desugaring and
 +    /// macro, it has been allowed in the mean time.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let _x = 0;
 +    /// let y = _x + 1; // Here we are using `_x`, even though it has a leading
 +    ///                 // underscore. We should rename `_x` to `x`
 +    /// ```
 +    pub USED_UNDERSCORE_BINDING,
 +    pedantic,
 +    "using a binding which is prefixed with an underscore"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for the use of short circuit boolean conditions as
 +    /// a
 +    /// statement.
 +    ///
 +    /// **Why is this bad?** Using a short circuit boolean condition as a statement
 +    /// may hide the fact that the second part is executed or not depending on the
 +    /// outcome of the first part.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// f() && g(); // We should write `if f() { g(); }`.
 +    /// ```
 +    pub SHORT_CIRCUIT_STATEMENT,
 +    complexity,
 +    "using a short circuit boolean condition as a statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Catch casts from `0` to some pointer type
 +    ///
 +    /// **Why is this bad?** This generally means `null` and is better expressed as
 +    /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// let a = 0 as *const u32;
 +    ///
 +    /// // Good
 +    /// let a = std::ptr::null::<u32>();
 +    /// ```
 +    pub ZERO_PTR,
 +    style,
 +    "using `0 as *{const, mut} T`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for (in-)equality comparisons on floating-point
 +    /// value and constant, except in functions called `*eq*` (which probably
 +    /// implement equality for a type involving floats).
 +    ///
 +    /// **Why is this bad?** Floating point calculations are usually imprecise, so
 +    /// asking if two values are *exactly* equal is asking for trouble. For a good
 +    /// guide on what to do, see [the floating point
 +    /// guide](http://www.floating-point-gui.de/errors/comparison).
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x: f64 = 1.0;
 +    /// const ONE: f64 = 1.00;
 +    ///
 +    /// // Bad
 +    /// if x == ONE { } // where both are floats
 +    ///
 +    /// // Good
 +    /// let error = f64::EPSILON; // Use an epsilon for comparison
 +    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
 +    /// // let error = std::f64::EPSILON;
 +    /// if (x - ONE).abs() < error { }
 +    /// ```
 +    pub FLOAT_CMP_CONST,
 +    restriction,
 +    "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
 +}
 +
 +declare_lint_pass!(MiscLints => [
 +    TOPLEVEL_REF_ARG,
 +    CMP_NAN,
 +    FLOAT_CMP,
 +    CMP_OWNED,
 +    MODULO_ONE,
 +    USED_UNDERSCORE_BINDING,
 +    SHORT_CIRCUIT_STATEMENT,
 +    ZERO_PTR,
 +    FLOAT_CMP_CONST
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MiscLints {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        k: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        _: Span,
 +        _: HirId,
 +    ) {
 +        if let FnKind::Closure(_) = k {
 +            // Does not apply to closures
 +            return;
 +        }
 +        for arg in iter_input_pats(decl, body) {
 +            if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
 +                span_lint(
 +                    cx,
 +                    TOPLEVEL_REF_ARG,
 +                    arg.pat.span,
 +                    "`ref` directly on a function argument is ignored. \
 +                    Consider using a reference type instead.",
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
 +        if_chain! {
 +            if let StmtKind::Local(ref local) = stmt.kind;
 +            if let PatKind::Binding(an, .., name, None) = local.pat.kind;
 +            if let Some(ref init) = local.init;
 +            if !higher::is_from_for_desugar(local);
 +            then {
 +                if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
 +                    let sugg_init = if init.span.from_expansion() {
 +                        Sugg::hir_with_macro_callsite(cx, init, "..")
 +                    } else {
 +                        Sugg::hir(cx, init, "..")
 +                    };
 +                    let (mutopt, initref) = if an == BindingAnnotation::RefMut {
 +                        ("mut ", sugg_init.mut_addr())
 +                    } else {
 +                        ("", sugg_init.addr())
 +                    };
 +                    let tyopt = if let Some(ref ty) = local.ty {
 +                        format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_"))
 +                    } else {
 +                        String::new()
 +                    };
 +                    span_lint_hir_and_then(
 +                        cx,
 +                        TOPLEVEL_REF_ARG,
 +                        init.hir_id,
 +                        local.pat.span,
 +                        "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
 +                        |diag| {
 +                            diag.span_suggestion(
 +                                stmt.span,
 +                                "try",
 +                                format!(
 +                                    "let {name}{tyopt} = {initref};",
 +                                    name=snippet(cx, name.span, "_"),
 +                                    tyopt=tyopt,
 +                                    initref=initref,
 +                                ),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    );
 +                }
 +            }
 +        };
 +        if_chain! {
 +            if let StmtKind::Semi(ref expr) = stmt.kind;
 +            if let ExprKind::Binary(ref binop, ref a, ref b) = expr.kind;
 +            if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
 +            if let Some(sugg) = Sugg::hir_opt(cx, a);
 +            then {
 +                span_lint_and_then(cx,
 +                    SHORT_CIRCUIT_STATEMENT,
 +                    stmt.span,
 +                    "boolean short circuit operator in statement may be clearer using an explicit test",
 +                    |diag| {
 +                        let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
 +                        diag.span_suggestion(
 +                            stmt.span,
 +                            "replace it with",
 +                            format!(
 +                                "if {} {{ {}; }}",
 +                                sugg,
 +                                &snippet(cx, b.span, ".."),
 +                            ),
 +                            Applicability::MachineApplicable, // snippet
 +                        );
 +                    });
 +            }
 +        };
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        match expr.kind {
 +            ExprKind::Cast(ref e, ref ty) => {
 +                check_cast(cx, expr.span, e, ty);
 +                return;
 +            },
 +            ExprKind::Binary(ref cmp, ref left, ref right) => {
 +                let op = cmp.node;
 +                if op.is_comparison() {
 +                    check_nan(cx, left, expr);
 +                    check_nan(cx, right, expr);
 +                    check_to_owned(cx, left, right, true);
 +                    check_to_owned(cx, right, left, false);
 +                }
 +                if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
 +                    if is_allowed(cx, left) || is_allowed(cx, right) {
 +                        return;
 +                    }
 +
 +                    // Allow comparing the results of signum()
 +                    if is_signum(cx, left) && is_signum(cx, right) {
 +                        return;
 +                    }
 +
 +                    if let Some(name) = get_item_name(cx, expr) {
 +                        let name = name.as_str();
 +                        if name == "eq"
 +                            || name == "ne"
 +                            || name == "is_nan"
 +                            || name.starts_with("eq_")
 +                            || name.ends_with("_eq")
 +                        {
 +                            return;
 +                        }
 +                    }
 +                    let is_comparing_arrays = is_array(cx, left) || is_array(cx, right);
 +                    let (lint, msg) = get_lint_and_message(
 +                        is_named_constant(cx, left) || is_named_constant(cx, right),
 +                        is_comparing_arrays,
 +                    );
 +                    span_lint_and_then(cx, lint, expr.span, msg, |diag| {
 +                        let lhs = Sugg::hir(cx, left, "..");
 +                        let rhs = Sugg::hir(cx, right, "..");
 +
 +                        if !is_comparing_arrays {
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "consider comparing them within some error",
 +                                format!(
 +                                    "({}).abs() {} error",
 +                                    lhs - rhs,
 +                                    if op == BinOpKind::Eq { '<' } else { '>' }
 +                                ),
 +                                Applicability::HasPlaceholders, // snippet
 +                            );
 +                        }
 +                        diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error`");
 +                    });
 +                } else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) {
 +                    span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
 +                }
 +            },
 +            _ => {},
 +        }
 +        if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) {
 +            // Don't lint things expanded by #[derive(...)], etc or `await` desugaring
 +            return;
 +        }
 +        let binding = match expr.kind {
++            ExprKind::Path(ref qpath) if !matches!(qpath, hir::QPath::LangItem(..)) => {
 +                let binding = last_path_segment(qpath).ident.as_str();
 +                if binding.starts_with('_') &&
 +                    !binding.starts_with("__") &&
 +                    binding != "_result" && // FIXME: #944
 +                    is_used(cx, expr) &&
 +                    // don't lint if the declaration is in a macro
 +                    non_macro_local(cx, cx.qpath_res(qpath, expr.hir_id))
 +                {
 +                    Some(binding)
 +                } else {
 +                    None
 +                }
 +            },
 +            ExprKind::Field(_, ident) => {
 +                let name = ident.as_str();
 +                if name.starts_with('_') && !name.starts_with("__") {
 +                    Some(name)
 +                } else {
 +                    None
 +                }
 +            },
 +            _ => None,
 +        };
 +        if let Some(binding) = binding {
 +            span_lint(
 +                cx,
 +                USED_UNDERSCORE_BINDING,
 +                expr.span,
 +                &format!(
 +                    "used binding `{}` which is prefixed with an underscore. A leading \
 +                     underscore signals that a binding will not be used.",
 +                    binding
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +fn get_lint_and_message(
 +    is_comparing_constants: bool,
 +    is_comparing_arrays: bool,
 +) -> (&'static rustc_lint::Lint, &'static str) {
 +    if is_comparing_constants {
 +        (
 +            FLOAT_CMP_CONST,
 +            if is_comparing_arrays {
 +                "strict comparison of `f32` or `f64` constant arrays"
 +            } else {
 +                "strict comparison of `f32` or `f64` constant"
 +            },
 +        )
 +    } else {
 +        (
 +            FLOAT_CMP,
 +            if is_comparing_arrays {
 +                "strict comparison of `f32` or `f64` arrays"
 +            } else {
 +                "strict comparison of `f32` or `f64`"
 +            },
 +        )
 +    }
 +}
 +
 +fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
 +    if_chain! {
 +        if !in_constant(cx, cmp_expr.hir_id);
 +        if let Some((value, _)) = constant(cx, cx.typeck_results(), expr);
 +        then {
 +            let needs_lint = match value {
 +                Constant::F32(num) => num.is_nan(),
 +                Constant::F64(num) => num.is_nan(),
 +                _ => false,
 +            };
 +
 +            if needs_lint {
 +                span_lint(
 +                    cx,
 +                    CMP_NAN,
 +                    cmp_expr.span,
 +                    "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +    if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) {
 +        res
 +    } else {
 +        false
 +    }
 +}
 +
 +fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +    match constant(cx, cx.typeck_results(), expr) {
 +        Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
 +        Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
 +        Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
 +            Constant::F32(f) => *f == 0.0 || (*f).is_infinite(),
 +            Constant::F64(f) => *f == 0.0 || (*f).is_infinite(),
 +            _ => false,
 +        }),
 +        _ => false,
 +    }
 +}
 +
 +// Return true if `expr` is the result of `signum()` invoked on a float value.
 +fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    // The negation of a signum is still a signum
 +    if let ExprKind::Unary(UnOp::UnNeg, ref child_expr) = expr.kind {
 +        return is_signum(cx, &child_expr);
 +    }
 +
 +    if_chain! {
 +        if let ExprKind::MethodCall(ref method_name, _, ref expressions, _) = expr.kind;
 +        if sym!(signum) == method_name.ident.name;
 +        // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
 +        // the method call)
 +        then {
 +            return is_float(cx, &expressions[0]);
 +        }
 +    }
 +    false
 +}
 +
 +fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind;
 +
 +    if let ty::Array(arr_ty, _) = value {
 +        return matches!(arr_ty.kind, ty::Float(_));
 +    };
 +
 +    matches!(value, ty::Float(_))
 +}
 +
 +fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind, ty::Array(_, _))
 +}
 +
 +fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
 +    #[derive(Default)]
 +    struct EqImpl {
 +        ty_eq_other: bool,
 +        other_eq_ty: bool,
 +    }
 +
 +    impl EqImpl {
 +        fn is_implemented(&self) -> bool {
 +            self.ty_eq_other || self.other_eq_ty
 +        }
 +    }
 +
 +    fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> {
 +        cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl {
 +            ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]),
 +            other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]),
 +        })
 +    }
 +
 +    let (arg_ty, snip) = match expr.kind {
 +        ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
 +            if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
 +                (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
 +            } else {
 +                return;
 +            }
 +        },
 +        ExprKind::Call(ref path, ref v) if v.len() == 1 => {
 +            if let ExprKind::Path(ref path) = path.kind {
 +                if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
 +                    (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
 +                } else {
 +                    return;
 +                }
 +            } else {
 +                return;
 +            }
 +        },
 +        _ => return,
 +    };
 +
 +    let other_ty = cx.typeck_results().expr_ty(other);
 +
 +    let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
 +    let with_deref = arg_ty
 +        .builtin_deref(true)
 +        .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
 +        .unwrap_or_default();
 +
 +    if !with_deref.is_implemented() && !without_deref.is_implemented() {
 +        return;
 +    }
 +
 +    let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _));
 +
 +    let lint_span = if other_gets_derefed {
 +        expr.span.to(other.span)
 +    } else {
 +        expr.span
 +    };
 +
 +    span_lint_and_then(
 +        cx,
 +        CMP_OWNED,
 +        lint_span,
 +        "this creates an owned instance just for comparison",
 +        |diag| {
 +            // This also catches `PartialEq` implementations that call `to_owned`.
 +            if other_gets_derefed {
 +                diag.span_label(lint_span, "try implementing the comparison without allocating");
 +                return;
 +            }
 +
 +            let expr_snip;
 +            let eq_impl;
 +            if with_deref.is_implemented() {
 +                expr_snip = format!("*{}", snip);
 +                eq_impl = with_deref;
 +            } else {
 +                expr_snip = snip.to_string();
 +                eq_impl = without_deref;
 +            };
 +
 +            let span;
 +            let hint;
 +            if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
 +                span = expr.span;
 +                hint = expr_snip;
 +            } else {
 +                span = expr.span.to(other.span);
 +                if eq_impl.ty_eq_other {
 +                    hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
 +                } else {
 +                    hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
 +                }
 +            }
 +
 +            diag.span_suggestion(
 +                span,
 +                "try",
 +                hint,
 +                Applicability::MachineApplicable, // snippet
 +            );
 +        },
 +    );
 +}
 +
 +/// Heuristic to see if an expression is used. Should be compatible with
 +/// `unused_variables`'s idea
 +/// of what it means for an expression to be "used".
 +fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind {
 +        ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr),
 +        _ => is_used(cx, parent),
 +    })
 +}
 +
 +/// Tests whether an expression is in a macro expansion (e.g., something
 +/// generated by `#[derive(...)]` or the like).
 +fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
 +    use rustc_span::hygiene::MacroKind;
 +    if expr.span.from_expansion() {
 +        let data = expr.span.ctxt().outer_expn_data();
 +        matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Tests whether `res` is a variable defined outside a macro.
 +fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
 +    if let def::Res::Local(id) = res {
 +        !cx.tcx.hir().span(id).from_expansion()
 +    } else {
 +        false
 +    }
 +}
 +
 +fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
 +    if_chain! {
 +        if let TyKind::Ptr(ref mut_ty) = ty.kind;
 +        if let ExprKind::Lit(ref lit) = e.kind;
 +        if let LitKind::Int(0, _) = lit.node;
 +        if !in_constant(cx, e.hir_id);
 +        then {
 +            let (msg, sugg_fn) = match mut_ty.mutbl {
 +                Mutability::Mut => ("`0 as *mut _` detected", "std::ptr::null_mut"),
 +                Mutability::Not => ("`0 as *const _` detected", "std::ptr::null"),
 +            };
 +
 +            let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
 +                (format!("{}()", sugg_fn), Applicability::MachineApplicable)
 +            } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
 +                (format!("{}::<{}>()", sugg_fn, mut_ty_snip), Applicability::MachineApplicable)
 +            } else {
 +                // `MaybeIncorrect` as type inference may not work with the suggested code
 +                (format!("{}()", sugg_fn), Applicability::MaybeIncorrect)
 +            };
 +            span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
 +        }
 +    }
 +}
index b8dc5081632972827f9fc9203246dabc8649d096,0000000000000000000000000000000000000000..c506440ed7987e48c7733262abbc12ac78805826
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,88 @@@
-     /// **Why is this bad?** The immutable reference rules out all other references
-     /// to the value. Also the code misleads about the intent of the call site.
 +use crate::utils::span_lint;
 +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::subst::Subst;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Detects passing a mutable reference to a function that only
 +    /// requires an immutable reference.
 +    ///
-                 check_arguments(cx, arguments, method_type, &path.ident.as_str())
++    /// **Why is this bad?** The mutable reference rules out all other references to
++    /// the value. Also the code misleads about the intent of the call site.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// // Bad
 +    /// my_vec.push(&mut value)
 +    ///
 +    /// // Good
 +    /// my_vec.push(&value)
 +    /// ```
 +    pub UNNECESSARY_MUT_PASSED,
 +    style,
 +    "an argument passed as a mutable reference although the callee only demands an immutable reference"
 +}
 +
 +declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        match e.kind {
 +            ExprKind::Call(ref fn_expr, ref arguments) => {
 +                if let ExprKind::Path(ref path) = fn_expr.kind {
 +                    check_arguments(
 +                        cx,
 +                        arguments,
 +                        cx.typeck_results().expr_ty(fn_expr),
 +                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
++                        "function",
 +                    );
 +                }
 +            },
 +            ExprKind::MethodCall(ref path, _, ref arguments, _) => {
 +                let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
 +                let substs = cx.typeck_results().node_substs(e.hir_id);
 +                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
- fn check_arguments<'tcx>(cx: &LateContext<'tcx>, arguments: &[Expr<'_>], type_definition: Ty<'tcx>, name: &str) {
++                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
 +            },
 +            _ => (),
 +        }
 +    }
 +}
 +
-                                 &format!("The function/method `{}` doesn't need a mutable reference", name),
++fn check_arguments<'tcx>(
++    cx: &LateContext<'tcx>,
++    arguments: &[Expr<'_>],
++    type_definition: Ty<'tcx>,
++    name: &str,
++    fn_kind: &str,
++) {
 +    match type_definition.kind {
 +        ty::FnDef(..) | ty::FnPtr(_) => {
 +            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
 +            for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
 +                match parameter.kind {
 +                    ty::Ref(_, _, Mutability::Not)
 +                    | ty::RawPtr(ty::TypeAndMut {
 +                        mutbl: Mutability::Not, ..
 +                    }) => {
 +                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
 +                            span_lint(
 +                                cx,
 +                                UNNECESSARY_MUT_PASSED,
 +                                argument.span,
++                                &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name),
 +                            );
 +                        }
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        },
 +        _ => (),
 +    }
 +}
index 568898aa5c9b7773f4e0fb53679def984114065b,0000000000000000000000000000000000000000..21efee71269862484f60ca618249bb067dd363e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,98 @@@
-                         "Consider using an `{}` instead of a `Mutex` here. If you just want the locking \
-                          behavior and not the internal type, consider using `Mutex<()>`.",
 +//! Checks for uses of mutex where an atomic value could be used
 +//!
 +//! This lint is **warn** by default
 +
 +use crate::utils::{is_type_diagnostic_item, span_lint};
 +use rustc_ast::ast;
 +use rustc_hir::Expr;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do.
 +    ///
 +    /// **Why is this bad?** Using a mutex just to make access to a plain bool or
 +    /// reference sequential is shooting flies with cannons.
 +    /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
 +    /// faster.
 +    ///
 +    /// **Known problems:** This lint cannot detect if the mutex is actually used
 +    /// for waiting before a critical section.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let y = true;
 +    ///
 +    /// // Bad
 +    /// # use std::sync::Mutex;
 +    /// let x = Mutex::new(&y);
 +    ///
 +    /// // Good
 +    /// # use std::sync::atomic::AtomicBool;
 +    /// let x = AtomicBool::new(y);
 +    /// ```
 +    pub MUTEX_ATOMIC,
 +    perf,
 +    "using a mutex where an atomic value could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral
 +    /// type.
 +    ///
 +    /// **Why is this bad?** Using a mutex just to make access to a plain integer
 +    /// sequential is
 +    /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
 +    ///
 +    /// **Known problems:** This lint cannot detect if the mutex is actually used
 +    /// for waiting before a critical section.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::sync::Mutex;
 +    /// let x = Mutex::new(0usize);
 +    ///
 +    /// // Good
 +    /// # use std::sync::atomic::AtomicUsize;
 +    /// let x = AtomicUsize::new(0usize);
 +    /// ```
 +    pub MUTEX_INTEGER,
 +    nursery,
 +    "using a mutex for an integer type"
 +}
 +
 +declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Mutex {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let ty = cx.typeck_results().expr_ty(expr);
 +        if let ty::Adt(_, subst) = ty.kind {
 +            if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) {
 +                let mutex_param = subst.type_at(0);
 +                if let Some(atomic_name) = get_atomic_name(mutex_param) {
 +                    let msg = format!(
++                        "consider using an `{}` instead of a `Mutex` here; if you just want the locking \
++                         behavior and not the internal type, consider using `Mutex<()>`",
 +                        atomic_name
 +                    );
 +                    match mutex_param.kind {
 +                        ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
 +                        ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
 +                        _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
 +                    };
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
 +    match ty.kind {
 +        ty::Bool => Some("AtomicBool"),
 +        ty::Uint(_) => Some("AtomicUsize"),
 +        ty::Int(_) => Some("AtomicIsize"),
 +        ty::RawPtr(_) => Some("AtomicPtr"),
 +        _ => None,
 +    }
 +}
index 031d69e86a13edb2c7c5406127dcf67f6d6bd65d,0000000000000000000000000000000000000000..f1df634701dd25d5c7a8e5dfcaa31abaad210426
mode 100644,000000..100644
--- /dev/null
@@@ -1,261 -1,0 +1,274 @@@
-                             dereferenced_expr = parent_expr;
 +//! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
 +//!
 +//! This lint is **deny** by default.
 +
 +use std::ptr;
 +
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass, Lint};
 +use rustc_middle::ty::adjustment::Adjust;
 +use rustc_middle::ty::{Ty, TypeFlags};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{InnerSpan, Span, DUMMY_SP};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for declaration of `const` items which is interior
 +    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
 +    ///
 +    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
 +    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
 +    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
 +    /// these types in the first place.
 +    ///
 +    /// The `const` should better be replaced by a `static` item if a global
 +    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
 +    ///
 +    /// **Known problems:** A "non-constant" const item is a legacy way to supply an
 +    /// initialized value to downstream `static` items (e.g., the
 +    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
 +    /// and this lint should be suppressed.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 +    ///
 +    /// // Bad.
 +    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
 +    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
 +    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
 +    ///
 +    /// // Good.
 +    /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
 +    /// STATIC_ATOM.store(9, SeqCst);
 +    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
 +    /// ```
 +    pub DECLARE_INTERIOR_MUTABLE_CONST,
 +    correctness,
 +    "declaring `const` with interior mutability"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
 +    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
 +    ///
 +    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
 +    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
 +    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
 +    /// these types in the first place.
 +    ///
 +    /// The `const` value should be stored inside a `static` item.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 +    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
 +    ///
 +    /// // Bad.
 +    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
 +    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
 +    ///
 +    /// // Good.
 +    /// static STATIC_ATOM: AtomicUsize = CONST_ATOM;
 +    /// STATIC_ATOM.store(9, SeqCst);
 +    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
 +    /// ```
 +    pub BORROW_INTERIOR_MUTABLE_CONST,
 +    correctness,
 +    "referencing `const` with interior mutability"
 +}
 +
 +#[allow(dead_code)]
 +#[derive(Copy, Clone)]
 +enum Source {
 +    Item { item: Span },
 +    Assoc { item: Span, ty: Span },
 +    Expr { expr: Span },
 +}
 +
 +impl Source {
 +    #[must_use]
 +    fn lint(&self) -> (&'static Lint, &'static str, Span) {
 +        match self {
 +            Self::Item { item } | Self::Assoc { item, .. } => (
 +                DECLARE_INTERIOR_MUTABLE_CONST,
 +                "a `const` item should never be interior mutable",
 +                *item,
 +            ),
 +            Self::Expr { expr } => (
 +                BORROW_INTERIOR_MUTABLE_CONST,
 +                "a `const` item with interior mutability should not be borrowed",
 +                *expr,
 +            ),
 +        }
 +    }
 +}
 +
 +fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
 +    if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
 +        // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
 +        // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
 +        // as well.
 +        return;
 +    }
 +
 +    let (lint, msg, span) = source.lint();
 +    span_lint_and_then(cx, lint, span, msg, |diag| {
 +        if span.from_expansion() {
 +            return; // Don't give suggestions into macros.
 +        }
 +        match source {
 +            Source::Item { .. } => {
 +                let const_kw_span = span.from_inner(InnerSpan::new(0, 5));
 +                diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
 +            },
 +            Source::Assoc { ty: ty_span, .. } => {
 +                if ty.flags.intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
 +                    diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
 +                }
 +            },
 +            Source::Expr { .. } => {
 +                diag.help("assign this const to a local or static variable, and use the variable here");
 +            },
 +        }
 +    });
 +}
 +
 +declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
 +
 +impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
 +        if let ItemKind::Const(hir_ty, ..) = &it.kind {
 +            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 +            verify_ty_bound(cx, ty, Source::Item { item: it.span });
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
 +        if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
 +            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 +            verify_ty_bound(
 +                cx,
 +                ty,
 +                Source::Assoc {
 +                    ty: hir_ty.span,
 +                    item: trait_item.span,
 +                },
 +            );
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
 +        if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
 +            let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
 +            let item = cx.tcx.hir().expect_item(item_hir_id);
 +            // Ensure the impl is an inherent impl.
 +            if let ItemKind::Impl { of_trait: None, .. } = item.kind {
 +                let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 +                verify_ty_bound(
 +                    cx,
 +                    ty,
 +                    Source::Assoc {
 +                        ty: hir_ty.span,
 +                        item: impl_item.span,
 +                    },
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Path(qpath) = &expr.kind {
 +            // Only lint if we use the const item inside a function.
 +            if in_constant(cx, expr.hir_id) {
 +                return;
 +            }
 +
 +            // Make sure it is a const item.
 +            match qpath_res(cx, qpath, expr.hir_id) {
 +                Res::Def(DefKind::Const | DefKind::AssocConst, _) => {},
 +                _ => return,
 +            };
 +
 +            // Climb up to resolve any field access and explicit referencing.
 +            let mut cur_expr = expr;
 +            let mut dereferenced_expr = expr;
 +            let mut needs_check_adjustment = true;
 +            loop {
 +                let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id);
 +                if parent_id == cur_expr.hir_id {
 +                    break;
 +                }
 +                if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find(parent_id) {
 +                    match &parent_expr.kind {
 +                        ExprKind::AddrOf(..) => {
 +                            // `&e` => `e` must be referenced.
 +                            needs_check_adjustment = false;
 +                        },
 +                        ExprKind::Field(..) => {
 +                            needs_check_adjustment = true;
++
++                            // Check whether implicit dereferences happened;
++                            // if so, no need to go further up
++                            // because of the same reason as the `ExprKind::Unary` case.
++                            if cx
++                                .typeck_results()
++                                .expr_adjustments(dereferenced_expr)
++                                .iter()
++                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
++                            {
++                                break;
++                            }
++
++                            dereferenced_expr = parent_expr;
 +                        },
 +                        ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
 +                            // `e[i]` => desugared to `*Index::index(&e, i)`,
 +                            // meaning `e` must be referenced.
 +                            // no need to go further up since a method call is involved now.
 +                            needs_check_adjustment = false;
 +                            break;
 +                        },
 +                        ExprKind::Unary(UnOp::UnDeref, _) => {
 +                            // `*e` => desugared to `*Deref::deref(&e)`,
 +                            // meaning `e` must be referenced.
 +                            // no need to go further up since a method call is involved now.
 +                            needs_check_adjustment = false;
 +                            break;
 +                        },
 +                        _ => break,
 +                    }
 +                    cur_expr = parent_expr;
 +                } else {
 +                    break;
 +                }
 +            }
 +
 +            let ty = if needs_check_adjustment {
 +                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
 +                if let Some(i) = adjustments
 +                    .iter()
 +                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
 +                {
 +                    if i == 0 {
 +                        cx.typeck_results().expr_ty(dereferenced_expr)
 +                    } else {
 +                        adjustments[i - 1].target
 +                    }
 +                } else {
 +                    // No borrow adjustments means the entire const is moved.
 +                    return;
 +                }
 +            } else {
 +                cx.typeck_results().expr_ty(dereferenced_expr)
 +            };
 +
 +            verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
 +        }
 +    }
 +}
index 4797771e7bdbb4aa9e95dba4f3a00c9f587cda42,0000000000000000000000000000000000000000..c9d18c3cb7287551e439bb15d3b57d05d29806e4
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,159 @@@
-         if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind {
-             if let ExprKind::MethodCall(ref path_segment, ref args, _) = rhs.kind {
 +use crate::utils::{snippet_with_applicability, span_lint_and_sugg};
++use if_chain::if_chain;
 +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +
 +const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [
 +    "asin",
 +    "asinh",
 +    "atan",
 +    "atanh",
 +    "cbrt",
 +    "fract",
 +    "round",
 +    "signum",
 +    "sin",
 +    "sinh",
 +    "tan",
 +    "tanh",
 +    "to_degrees",
 +    "to_radians",
 +];
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for operations where precedence may be unclear
 +    /// and suggests to add parentheses. Currently it catches the following:
 +    /// * mixed usage of arithmetic and bit shifting/combining operators without
 +    /// parentheses
 +    /// * a "negative" numeric literal (which is really a unary `-` followed by a
 +    /// numeric literal)
 +    ///   followed by a method call
 +    ///
 +    /// **Why is this bad?** Not everyone knows the precedence of those operators by
 +    /// heart, so expressions like these may trip others trying to reason about the
 +    /// code.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
 +    /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
 +    pub PRECEDENCE,
 +    complexity,
 +    "operations where precedence may be unclear"
 +}
 +
 +declare_lint_pass!(Precedence => [PRECEDENCE]);
 +
 +impl EarlyLintPass for Precedence {
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.kind {
 +            let span_sugg = |expr: &Expr, sugg, appl| {
 +                span_lint_and_sugg(
 +                    cx,
 +                    PRECEDENCE,
 +                    expr.span,
 +                    "operator precedence can trip the unwary",
 +                    "consider parenthesizing your expression",
 +                    sugg,
 +                    appl,
 +                );
 +            };
 +
 +            if !is_bit_op(op) {
 +                return;
 +            }
 +            let mut applicability = Applicability::MachineApplicable;
 +            match (is_arith_expr(left), is_arith_expr(right)) {
 +                (true, true) => {
 +                    let sugg = format!(
 +                        "({}) {} ({})",
 +                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
 +                        op.to_string(),
 +                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
 +                    );
 +                    span_sugg(expr, sugg, applicability);
 +                },
 +                (true, false) => {
 +                    let sugg = format!(
 +                        "({}) {} {}",
 +                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
 +                        op.to_string(),
 +                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
 +                    );
 +                    span_sugg(expr, sugg, applicability);
 +                },
 +                (false, true) => {
 +                    let sugg = format!(
 +                        "{} {} ({})",
 +                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
 +                        op.to_string(),
 +                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
 +                    );
 +                    span_sugg(expr, sugg, applicability);
 +                },
 +                (false, false) => (),
 +            }
 +        }
 +
-                 if let Some(slf) = args.first() {
-                     if let ExprKind::Lit(ref lit) = slf.kind {
-                         match lit.kind {
-                             LitKind::Int(..) | LitKind::Float(..) => {
-                                 if ALLOWED_ODD_FUNCTIONS
-                                     .iter()
-                                     .any(|odd_function| **odd_function == *path_segment_str)
-                                 {
-                                     return;
-                                 }
-                                 let mut applicability = Applicability::MachineApplicable;
-                                 span_lint_and_sugg(
-                                     cx,
-                                     PRECEDENCE,
-                                     expr.span,
-                                     "unary minus has lower precedence than method call",
-                                     "consider adding parentheses to clarify your intent",
-                                     format!(
-                                         "-({})",
-                                         snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
-                                     ),
-                                     applicability,
-                                 );
-                             },
-                             _ => (),
-                         }
-                     }
++        if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind {
++            let mut arg = operand;
++
++            let mut all_odd = true;
++            while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
 +                let path_segment_str = path_segment.ident.name.as_str();
++                all_odd &= ALLOWED_ODD_FUNCTIONS
++                    .iter()
++                    .any(|odd_function| **odd_function == *path_segment_str);
++                arg = args.first().expect("A method always has a receiver.");
++            }
++
++            if_chain! {
++                if !all_odd;
++                if let ExprKind::Lit(lit) = &arg.kind;
++                if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
++                then {
++                    let mut applicability = Applicability::MachineApplicable;
++                    span_lint_and_sugg(
++                        cx,
++                        PRECEDENCE,
++                        expr.span,
++                        "unary minus has lower precedence than method call",
++                        "consider adding parentheses to clarify your intent",
++                        format!(
++                            "-({})",
++                            snippet_with_applicability(cx, operand.span, "..", &mut applicability)
++                        ),
++                        applicability,
++                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn is_arith_expr(expr: &Expr) -> bool {
 +    match expr.kind {
 +        ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op),
 +        _ => false,
 +    }
 +}
 +
 +#[must_use]
 +fn is_bit_op(op: BinOpKind) -> bool {
 +    use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr};
 +    matches!(op, BitXor | BitAnd | BitOr | Shl | Shr)
 +}
 +
 +#[must_use]
 +fn is_arith_op(op: BinOpKind) -> bool {
 +    use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub};
 +    matches!(op, Add | Sub | Mul | Div | Rem)
 +}
index 460d631fab0fdc62ac9207e3112c9bfb65383937,0000000000000000000000000000000000000000..7dafb1555dc6e7e187f62e44c1977de7dd2fd81d
mode 100644,000000..100644
--- /dev/null
@@@ -1,316 -1,0 +1,329 @@@
-     /// other crates referencing it you may not be aware. Carefully deprecate the
-     /// function before applying the lint suggestions in this case.
 +//! Checks for usage of  `&Vec[_]` and `&String`.
 +
 +use crate::utils::ptr::get_spans;
 +use crate::utils::{
 +    is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
 +    span_lint_and_then, walk_ptrs_hir_ty,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind,
 +    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
 +};
 +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 rustc_span::MultiSpan;
 +use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint checks for function arguments of type `&String`
 +    /// or `&Vec` unless the references are mutable. It will also suggest you
 +    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
 +    /// calls.
 +    ///
 +    /// **Why is this bad?** Requiring the argument to be of the specific size
 +    /// makes the function less useful for no benefit; slices in the form of `&[T]`
 +    /// or `&str` usually suffice and can be obtained from other types, too.
 +    ///
 +    /// **Known problems:** The lint does not follow data. So if you have an
 +    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
 +    /// changing that `.clone()` to `.to_owned()`.
 +    ///
 +    /// Other functions called from this function taking a `&String` or `&Vec`
 +    /// argument may also fail to compile if you change the argument. Applying
 +    /// this lint on them will fix the problem, but they may be in other crates.
 +    ///
++    /// One notable example of a function that may cause issues, and which cannot
++    /// easily be changed due to being in the standard library is `Vec::contains`.
++    /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
++    /// it will compile, but if a `&[T]` is passed then it will not compile.
++    ///
++    /// ```ignore
++    /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
++    ///     let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
++    ///
++    ///     vec_of_vecs.contains(v)
++    /// }
++    /// ```
++    ///
 +    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
 +    /// If you have them, you will get a compiler error after applying this lint's
 +    /// suggestions. You then have the choice to undo your changes or change the
 +    /// type of the reference.
 +    ///
 +    /// Note that if the function is part of your public interface, there may be
++    /// other crates referencing it, of which you may not be aware. Carefully
++    /// deprecate the function before applying the lint suggestions in this case.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// // Bad
 +    /// fn foo(&Vec<u32>) { .. }
 +    ///
 +    /// // Good
 +    /// fn foo(&[u32]) { .. }
 +    /// ```
 +    pub PTR_ARG,
 +    style,
 +    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint checks for equality comparisons with `ptr::null`
 +    ///
 +    /// **Why is this bad?** It's easier and more readable to use the inherent
 +    /// `.is_null()`
 +    /// method instead
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// // Bad
 +    /// if x == ptr::null {
 +    ///     ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// if x.is_null() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub CMP_NULL,
 +    style,
 +    "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint checks for functions that take immutable
 +    /// references and return mutable ones.
 +    ///
 +    /// **Why is this bad?** This is trivially unsound, as one can create two
 +    /// mutable references from the same (immutable!) source.
 +    /// This [error](https://github.com/rust-lang/rust/issues/39465)
 +    /// actually lead to an interim Rust release 1.15.1.
 +    ///
 +    /// **Known problems:** To be on the conservative side, if there's at least one
 +    /// mutable reference with the output lifetime, this lint will not trigger.
 +    /// In practice, this case is unlikely anyway.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// fn foo(&Foo) -> &mut Bar { .. }
 +    /// ```
 +    pub MUT_FROM_REF,
 +    correctness,
 +    "fns that create mutable refs from immutable ref args"
 +}
 +
 +declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Ptr {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
 +            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
 +            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id);
 +            if let Some(Node::Item(it)) = cx.tcx.hir().find(parent_item) {
 +                if let ItemKind::Impl { of_trait: Some(_), .. } = it.kind {
 +                    return; // ignore trait impls
 +                }
 +            }
 +            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
 +            let body_id = if let TraitFn::Provided(b) = *trait_method {
 +                Some(b)
 +            } else {
 +                None
 +            };
 +            check_fn(cx, &sig.decl, item.hir_id, body_id);
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind {
 +            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
 +                span_lint(
 +                    cx,
 +                    CMP_NULL,
 +                    expr.span,
 +                    "comparing with null is better expressed by the `.is_null()` method",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
 +    let sig = cx.tcx.fn_sig(fn_def_id);
 +    let fn_ty = sig.skip_binder();
 +    let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
 +
 +    for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
 +        // Honor the allow attribute on parameters. See issue 5644.
 +        if let Some(body) = &body {
 +            if is_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
 +                continue;
 +            }
 +        }
 +
 +        if let ty::Ref(_, ty, Mutability::Not) = ty.kind {
 +            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
 +                let mut ty_snippet = None;
 +                if_chain! {
 +                    if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
 +                    if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
 +                    then {
 +                        let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
 +                            GenericArg::Type(ty) => Some(ty),
 +                            _ => None,
 +                        }).collect();
 +                        if types.len() == 1 {
 +                            ty_snippet = snippet_opt(cx, types[0].span);
 +                        }
 +                    }
 +                };
 +                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PTR_ARG,
 +                        arg.span,
 +                        "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
 +                         with non-Vec-based slices.",
 +                        |diag| {
 +                            if let Some(ref snippet) = ty_snippet {
 +                                diag.span_suggestion(
 +                                    arg.span,
 +                                    "change this to",
 +                                    format!("&[{}]", snippet),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                            for (clonespan, suggestion) in spans {
 +                                diag.span_suggestion(
 +                                    clonespan,
 +                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
 +                                        Cow::Owned(format!("change `{}` to", x))
 +                                    }),
 +                                    suggestion.into(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    );
 +                }
 +            } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
 +                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PTR_ARG,
 +                        arg.span,
 +                        "writing `&String` instead of `&str` involves a new object where a slice will do.",
 +                        |diag| {
 +                            diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
 +                            for (clonespan, suggestion) in spans {
 +                                diag.span_suggestion_short(
 +                                    clonespan,
 +                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
 +                                        Cow::Owned(format!("change `{}` to", x))
 +                                    }),
 +                                    suggestion.into(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    );
 +                }
 +            } else if match_type(cx, ty, &paths::COW) {
 +                if_chain! {
 +                    if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
 +                    if let TyKind::Path(ref path) = ty.kind;
 +                    if let QPath::Resolved(None, ref pp) = *path;
 +                    if let [ref bx] = *pp.segments;
 +                    if let Some(ref params) = bx.args;
 +                    if !params.parenthesized;
 +                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
 +                        GenericArg::Type(ty) => Some(ty),
 +                        _ => None,
 +                    });
 +                    then {
 +                        let replacement = snippet_opt(cx, inner.span);
 +                        if let Some(r) = replacement {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                PTR_ARG,
 +                                arg.span,
 +                                "using a reference to `Cow` is not recommended.",
 +                                "change this to",
 +                                "&".to_owned() + &r,
 +                                Applicability::Unspecified,
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    if let FnRetTy::Return(ref ty) = decl.output {
 +        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
 +            let mut immutables = vec![];
 +            for (_, ref mutbl, ref argspan) in decl
 +                .inputs
 +                .iter()
 +                .filter_map(|ty| get_rptr_lm(ty))
 +                .filter(|&(lt, _, _)| lt.name == out.name)
 +            {
 +                if *mutbl == Mutability::Mut {
 +                    return;
 +                }
 +                immutables.push(*argspan);
 +            }
 +            if immutables.is_empty() {
 +                return;
 +            }
 +            span_lint_and_then(
 +                cx,
 +                MUT_FROM_REF,
 +                ty.span,
 +                "mutable borrow from immutable input(s)",
 +                |diag| {
 +                    let ms = MultiSpan::from_spans(immutables);
 +                    diag.span_note(ms, "immutable borrow here");
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
 +    if let TyKind::Rptr(ref lt, ref m) = ty.kind {
 +        Some((lt, m.mutbl, ty.span))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn is_null_path(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(ref pathexp, ref args) = expr.kind {
 +        if args.is_empty() {
 +            if let ExprKind::Path(ref path) = pathexp.kind {
 +                return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT);
 +            }
 +        }
 +    }
 +    false
 +}
index fb12c565afd863048bbcbc895f1abb4fbf36b082,0000000000000000000000000000000000000000..dbc676ae22408b139172a742361ca9ac7e511003
mode 100644,000000..100644
--- /dev/null
@@@ -1,204 -1,0 +1,204 @@@
-     higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability,
-     span_lint_and_sugg, SpanlessEq,
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +use crate::utils::sugg::Sugg;
 +use crate::utils::{
-                         if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
++    eq_expr_value, higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability,
++    span_lint_and_sugg,
 +};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for expressions that could be replaced by the question mark operator.
 +    ///
 +    /// **Why is this bad?** Question mark usage is more idiomatic.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// if option.is_none() {
 +    ///     return None;
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```ignore
 +    /// option?;
 +    /// ```
 +    pub QUESTION_MARK,
 +    style,
 +    "checks for expressions that could be replaced by the question mark operator"
 +}
 +
 +declare_lint_pass!(QuestionMark => [QUESTION_MARK]);
 +
 +impl QuestionMark {
 +    /// Checks if the given expression on the given context matches the following structure:
 +    ///
 +    /// ```ignore
 +    /// if option.is_none() {
 +    ///    return None;
 +    /// }
 +    /// ```
 +    ///
 +    /// If it matches, it will suggest to use the question mark operator instead
 +    fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let Some((if_expr, body, else_)) = higher::if_block(&expr);
 +            if let ExprKind::MethodCall(segment, _, args, _) = &if_expr.kind;
 +            if segment.ident.name == sym!(is_none);
 +            if Self::expression_returns_none(cx, body);
 +            if let Some(subject) = args.get(0);
 +            if Self::is_option(cx, subject);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
 +                let mut replacement: Option<String> = None;
 +                if let Some(else_) = else_ {
 +                    if_chain! {
 +                        if let ExprKind::Block(block, None) = &else_.kind;
 +                        if block.stmts.is_empty();
 +                        if let Some(block_expr) = &block.expr;
++                        if eq_expr_value(cx, subject, block_expr);
 +                        then {
 +                            replacement = Some(format!("Some({}?)", receiver_str));
 +                        }
 +                    }
 +                } else if Self::moves_by_default(cx, subject)
 +                    && !matches!(subject.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
 +                {
 +                    replacement = Some(format!("{}.as_ref()?;", receiver_str));
 +                } else {
 +                    replacement = Some(format!("{}?;", receiver_str));
 +                }
 +
 +                if let Some(replacement_str) = replacement {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        QUESTION_MARK,
 +                        expr.span,
 +                        "this block may be rewritten with the `?` operator",
 +                        "replace it with",
 +                        replacement_str,
 +                        applicability,
 +                    )
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Match(subject, arms, source) = &expr.kind;
 +            if *source == MatchSource::IfLetDesugar { contains_else_clause: true };
 +            if Self::is_option(cx, subject);
 +
 +            if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind;
 +            if match_qpath(path1, &["Some"]);
 +            if let PatKind::Binding(annot, _, bind, _) = &fields[0].kind;
 +            let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
 +
 +            if let ExprKind::Block(block, None) = &arms[0].body.kind;
 +            if block.stmts.is_empty();
 +            if let Some(trailing_expr) = &block.expr;
 +            if let ExprKind::Path(path) = &trailing_expr.kind;
 +            if match_qpath(path, &[&bind.as_str()]);
 +
 +            if let PatKind::Wild = arms[1].pat.kind;
 +            if Self::expression_returns_none(cx, arms[1].body);
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let receiver_str = snippet_with_applicability(cx, subject.span, "..", &mut applicability);
 +                let replacement = format!(
 +                    "{}{}?",
 +                    receiver_str,
 +                    if by_ref { ".as_ref()" } else { "" },
 +                );
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    QUESTION_MARK,
 +                    expr.span,
 +                    "this if-let-else may be rewritten with the `?` operator",
 +                    "replace it with",
 +                    replacement,
 +                    applicability,
 +                )
 +            }
 +        }
 +    }
 +
 +    fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        let expr_ty = cx.typeck_results().expr_ty(expression);
 +
 +        !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env)
 +    }
 +
 +    fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        let expr_ty = cx.typeck_results().expr_ty(expression);
 +
 +        is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
 +    }
 +
 +    fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        match expression.kind {
 +            ExprKind::Block(ref block, _) => {
 +                if let Some(return_expression) = Self::return_expression(block) {
 +                    return Self::expression_returns_none(cx, &return_expression);
 +                }
 +
 +                false
 +            },
 +            ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
 +            ExprKind::Path(ref qp) => {
 +                if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
 +                    cx.qpath_res(qp, expression.hir_id)
 +                {
 +                    return match_def_path(cx, def_id, &paths::OPTION_NONE);
 +                }
 +
 +                false
 +            },
 +            _ => false,
 +        }
 +    }
 +
 +    fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +        // Check if last expression is a return statement. Then, return the expression
 +        if_chain! {
 +            if block.stmts.len() == 1;
 +            if let Some(expr) = block.stmts.iter().last();
 +            if let StmtKind::Semi(ref expr) = expr.kind;
 +            if let ExprKind::Ret(ret_expr) = expr.kind;
 +            if let Some(ret_expr) = ret_expr;
 +
 +            then {
 +                return Some(ret_expr);
 +            }
 +        }
 +
 +        // Check for `return` without a semicolon.
 +        if_chain! {
 +            if block.stmts.is_empty();
 +            if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.kind);
 +            then {
 +                return Some(ret_expr);
 +            }
 +        }
 +
 +        None
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for QuestionMark {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        Self::check_is_none_and_early_return_none(cx, expr);
 +        Self::check_if_let_some_and_early_return_none(cx, expr);
 +    }
 +}
index 8aa478ea2d69f41aa77253cc4696827820fa2a7e,0000000000000000000000000000000000000000..49cb2ffc4e372a3f765e89e1f9fe4bf0f7740a23
mode 100644,000000..100644
--- /dev/null
@@@ -1,151 -1,0 +1,156 @@@
-                         "try not to call a closure in the expression where it is declared.",
 +use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_ast::visit as ast_visit;
 +use rustc_ast::visit::Visitor as AstVisitor;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit as hir_visit;
 +use rustc_hir::intravisit::Visitor as HirVisitor;
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Detects closures called in the same expression where they
 +    /// are defined.
 +    ///
 +    /// **Why is this bad?** It is unnecessarily adding to the expression's
 +    /// complexity.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// let a = (|| 42)()
 +    ///
 +    /// // Good
 +    /// let a = 42
 +    /// ```
 +    pub REDUNDANT_CLOSURE_CALL,
 +    complexity,
 +    "throwaway closures called in the expression they are defined"
 +}
 +
 +declare_lint_pass!(RedundantClosureCall => [REDUNDANT_CLOSURE_CALL]);
 +
 +// Used to find `return` statements or equivalents e.g., `?`
 +struct ReturnVisitor {
 +    found_return: bool,
 +}
 +
 +impl ReturnVisitor {
 +    #[must_use]
 +    fn new() -> Self {
 +        Self { found_return: false }
 +    }
 +}
 +
 +impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
 +    fn visit_expr(&mut self, ex: &'ast ast::Expr) {
 +        if let ast::ExprKind::Ret(_) = ex.kind {
 +            self.found_return = true;
 +        } else if let ast::ExprKind::Try(_) = ex.kind {
 +            self.found_return = true;
 +        }
 +
 +        ast_visit::walk_expr(self, ex)
 +    }
 +}
 +
 +impl EarlyLintPass for RedundantClosureCall {
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 +        if in_external_macro(cx.sess(), expr.span) {
 +            return;
 +        }
 +        if_chain! {
 +            if let ast::ExprKind::Call(ref paren, _) = expr.kind;
 +            if let ast::ExprKind::Paren(ref closure) = paren.kind;
 +            if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind;
 +            then {
 +                let mut visitor = ReturnVisitor::new();
 +                visitor.visit_expr(block);
 +                if !visitor.found_return {
 +                    span_lint_and_then(
 +                        cx,
 +                        REDUNDANT_CLOSURE_CALL,
 +                        expr.span,
-         fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>) -> usize {
-             struct ClosureUsageCount<'tcx> {
++                        "try not to call a closure in the expression where it is declared",
 +                        |diag| {
 +                            if decl.inputs.is_empty() {
 +                                let mut app = Applicability::MachineApplicable;
 +                                let hint =
 +                                    snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
 +                                diag.span_suggestion(expr.span, "try doing something like", hint, app);
 +                            }
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-             impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> {
++        fn count_closure_usage<'a, 'tcx>(
++            cx: &'a LateContext<'tcx>,
++            block: &'tcx hir::Block<'_>,
++            path: &'tcx hir::Path<'tcx>,
++        ) -> usize {
++            struct ClosureUsageCount<'a, 'tcx> {
++                cx: &'a LateContext<'tcx>,
 +                path: &'tcx hir::Path<'tcx>,
 +                count: usize,
 +            };
-                     hir_visit::NestedVisitorMap::None
++            impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
 +                type Map = Map<'tcx>;
 +
 +                fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
 +                    if_chain! {
 +                        if let hir::ExprKind::Call(ref closure, _) = expr.kind;
 +                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
 +                        if self.path.segments[0].ident == path.segments[0].ident
 +                            && self.path.res == path.res;
 +                        then {
 +                            self.count += 1;
 +                        }
 +                    }
 +                    hir_visit::walk_expr(self, expr);
 +                }
 +
 +                fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-             let mut closure_usage_count = ClosureUsageCount { path, count: 0 };
++                    hir_visit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +                }
 +            };
-                 if count_closure_usage(block, path) == 1;
++            let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 };
 +            closure_usage_count.visit_block(block);
 +            closure_usage_count.count
 +        }
 +
 +        for w in block.stmts.windows(2) {
 +            if_chain! {
 +                if let hir::StmtKind::Local(ref local) = w[0].kind;
 +                if let Option::Some(ref t) = local.init;
 +                if let hir::ExprKind::Closure(..) = t.kind;
 +                if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
 +                if let hir::StmtKind::Semi(ref second) = w[1].kind;
 +                if let hir::ExprKind::Assign(_, ref call, _) = second.kind;
 +                if let hir::ExprKind::Call(ref closure, _) = call.kind;
 +                if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
 +                if ident == path.segments[0].ident;
++                if count_closure_usage(cx, block, path) == 1;
 +                then {
 +                    span_lint(
 +                        cx,
 +                        REDUNDANT_CLOSURE_CALL,
 +                        second.span,
 +                        "closure called just once immediately after it was declared",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
index 77c206002ea790684217a3cc6404b69d7a14b7b3,0000000000000000000000000000000000000000..c0890018d46aba3abe8c9843d8a98cdffadf63dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,82 @@@
-             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
 +use crate::consts::{constant_context, Constant};
 +use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
 +    /// - `.to_string()` for `str`
 +    /// - `.clone()` for `String`
 +    /// - `.to_vec()` for `slice`
 +    ///
 +    /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").repeat(1);
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").clone();
 +    /// }
 +    /// ```
 +    pub REPEAT_ONCE,
 +    complexity,
 +    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
 +}
 +
 +declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
-             if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&args[1]);
-             if !in_macro(args[0].span);
++            if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
 +            if path.ident.name == sym!(repeat);
-                 let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
++            if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&count);
++            if !in_macro(receiver.span);
 +            then {
-                         format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)),
++                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&receiver));
 +                if ty.is_str() {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        REPEAT_ONCE,
 +                        expr.span,
 +                        "calling `repeat(1)` on str",
 +                        "consider using `.to_string()` instead",
-                         format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)),
++                        format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
 +                        Applicability::MachineApplicable,
 +                    );
 +                } else if ty.builtin_index().is_some() {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        REPEAT_ONCE,
 +                        expr.span,
 +                        "calling `repeat(1)` on slice",
 +                        "consider using `.to_vec()` instead",
-                         format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)),
++                        format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
 +                        Applicability::MachineApplicable,
 +                    );
 +                } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        REPEAT_ONCE,
 +                        expr.span,
 +                        "calling `repeat(1)` on a string literal",
 +                        "consider using `.clone()` instead",
++                        format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
index 8ed20995a70af1257708ba3b8b278dc08adbec8d,0000000000000000000000000000000000000000..a6e4252a0c82579b2c332cf8a31c2279ed9fcfcc
mode 100644,000000..100644
--- /dev/null
@@@ -1,283 -1,0 +1,289 @@@
- use rustc_ast::ast;
- use rustc_ast::visit::FnKind;
 +use if_chain::if_chain;
- use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
++use rustc_ast::ast::Attribute;
 +use rustc_errors::Applicability;
- use rustc_span::BytePos;
++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::source_map::Span;
- use crate::utils::{snippet_opt, span_lint_and_sugg, span_lint_and_then};
 +
-     /// **What it does:** Checks for return statements at the end of a block.
++use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then};
 +
 +declare_clippy_lint! {
-     /// **Why is this bad?** Removing the `return` and semicolon will make the code
++    /// **What it does:** Checks for `let`-bindings, which are subsequently
++    /// returned.
 +    ///
-     /// **Known problems:** If the computation returning the value borrows a local
-     /// variable, removing the `return` may run afoul of the borrow checker.
++    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
 +    /// more rusty.
 +    ///
-     /// fn foo(x: usize) -> usize {
-     ///     return x;
++    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
-     /// simplify to
-     /// ```rust
-     /// fn foo(x: usize) -> usize {
-     ///     x
++    /// fn foo() -> String {
++    ///     let x = String::new();
++    ///     x
 +    /// }
 +    /// ```
-     pub NEEDLESS_RETURN,
++    /// instead, use
++    /// ```
++    /// fn foo() -> String {
++    ///     String::new()
 +    /// }
 +    /// ```
-     "using a return statement like `return expr;` where an expression would suffice"
++    pub LET_AND_RETURN,
 +    style,
-     /// **What it does:** Checks for unit (`()`) expressions that can be removed.
++    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
 +}
 +
 +declare_clippy_lint! {
-     /// **Why is this bad?** Such expressions add no value, but can make the code
-     /// less readable. Depending on formatting they can make a `break` or `return`
-     /// statement look like a function call.
++    /// **What it does:** Checks for return statements at the end of a block.
 +    ///
-     /// **Known problems:** The lint currently misses unit return types in types,
-     /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`.
++    /// **Why is this bad?** Removing the `return` and semicolon will make the code
++    /// more rusty.
 +    ///
-     /// fn return_unit() -> () {
-     ///     ()
++    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
-     pub UNUSED_UNIT,
++    /// fn foo(x: usize) -> usize {
++    ///     return x;
 +    /// }
 +    /// ```
-     "needless unit expression"
++    /// simplify to
++    /// ```rust
++    /// fn foo(x: usize) -> usize {
++    ///     x
++    /// }
++    /// ```
++    pub NEEDLESS_RETURN,
 +    style,
- declare_lint_pass!(Return => [NEEDLESS_RETURN, UNUSED_UNIT]);
++    "using a return statement like `return expr;` where an expression would suffice"
 +}
 +
 +#[derive(PartialEq, Eq, Copy, Clone)]
 +enum RetReplacement {
 +    Empty,
 +    Block,
 +}
 +
- impl Return {
-     // Check the final stmt or expr in a block for unnecessary return.
-     fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-         if let Some(stmt) = block.stmts.last() {
-             match stmt.kind {
-                 ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
-                     self.check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
-                 },
-                 _ => (),
++declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
 +
-     // Check the final expression in a block if it's a return.
-     fn check_final_expr(
++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 local.attrs.is_empty();
++            if let Some(initexpr) = &local.init;
++            if let PatKind::Binding(.., ident, _) = local.pat.kind;
++            if let ExprKind::Path(qpath) = &retexpr.kind;
++            if match_qpath(qpath, &[&*ident.name.as_str()]);
++            if !last_statement_borrows(cx, initexpr);
++            if !in_external_macro(cx.sess(), initexpr.span);
++            if !in_external_macro(cx.sess(), retexpr.span);
++            if !in_external_macro(cx.sess(), local.span);
++            if !in_macro(local.span);
++            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");
++                        }
++                    },
++                );
 +            }
 +        }
 +    }
 +
-         cx: &EarlyContext<'_>,
-         expr: &ast::Expr,
-         span: Option<Span>,
-         replacement: RetReplacement,
++    fn check_fn(
 +        &mut self,
-         match expr.kind {
-             // simple return is always "bad"
-             ast::ExprKind::Ret(ref inner) => {
-                 // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
-                 if !expr.attrs.iter().any(attr_is_cfg) {
-                     Self::emit_return_lint(
-                         cx,
-                         span.expect("`else return` is not possible"),
-                         inner.as_ref().map(|i| i.span),
-                         replacement,
-                     );
-                 }
-             },
-             // a whole block? check it!
-             ast::ExprKind::Block(ref block, _) => {
-                 self.check_block_return(cx, block);
-             },
-             // 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
-             ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
-                 self.check_block_return(cx, ifblock);
-                 self.check_final_expr(cx, elsexpr, None, RetReplacement::Empty);
-             },
-             // a match expr, check all arms
-             ast::ExprKind::Match(_, ref arms) => {
-                 for arm in arms {
-                     self.check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
++        cx: &LateContext<'tcx>,
++        kind: FnKind<'tcx>,
++        _: &'tcx FnDecl<'tcx>,
++        body: &'tcx Body<'tcx>,
++        _: Span,
++        _: HirId,
 +    ) {
-             _ => (),
++        match kind {
++            FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty),
++            FnKind::ItemFn(..) | FnKind::Method(..) => {
++                if let ExprKind::Block(ref block, _) = body.value.kind {
++                    check_block_return(cx, block);
 +                }
 +            },
-     fn emit_return_lint(cx: &EarlyContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
-         match inner_span {
-             Some(inner_span) => {
-                 if in_external_macro(cx.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);
-                     }
-                 })
++fn attr_is_cfg(attr: &Attribute) -> bool {
++    attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
++}
 +
-             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(
++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(ref expr) | StmtKind::Semi(ref expr) => {
++                check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
 +            },
-                         NEEDLESS_RETURN,
-                         ret_span,
-                         "unneeded `return` statement",
-                         "replace `return` with an empty block",
-                         "{}".to_string(),
-                         Applicability::MachineApplicable,
++            _ => (),
++        }
++    }
++}
++
++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;`
++            if !expr.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(ref block, _) => {
++            check_block_return(cx, block);
++        },
++        // 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(_, ref arms, source) => match source {
++            MatchSource::Normal => {
++                for arm in arms.iter() {
++                    check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
++                }
 +            },
- impl EarlyLintPass for Return {
-     fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
-         match kind {
-             FnKind::Fn(.., Some(block)) => self.check_block_return(cx, block),
-             FnKind::Closure(_, body) => self.check_final_expr(cx, body, Some(body.span), RetReplacement::Empty),
-             FnKind::Fn(.., None) => {},
-         }
-         if_chain! {
-             if let ast::FnRetTy::Ty(ref ty) = kind.decl().output;
-             if let ast::TyKind::Tup(ref vals) = ty.kind;
-             if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
-             then {
-                 lint_unneeded_unit_return(cx, ty, span);
++            MatchSource::IfDesugar {
++                contains_else_clause: true,
++            }
++            | MatchSource::IfLetDesugar {
++                contains_else_clause: true,
++            } => {
++                if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
++                    check_block_return(cx, ifblock);
++                }
++                check_final_expr(cx, arms[1].body, None, RetReplacement::Empty);
++            },
++            _ => (),
++        },
++        _ => (),
 +    }
 +}
 +
-         }
-     }
++fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
++    match inner_span {
++        Some(inner_span) => {
++            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
++                return;
 +            }
-     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-         if_chain! {
-             if let Some(ref stmt) = block.stmts.last();
-             if let ast::StmtKind::Expr(ref expr) = stmt.kind;
-             if is_unit_expr(expr) && !stmt.span.from_expansion();
-             then {
-                 let sp = expr.span;
 +
-                     UNUSED_UNIT,
-                     sp,
-                     "unneeded unit expression",
-                     "remove the final `()`",
++            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,
-             }
-         }
-     }
-     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-         match e.kind {
-             ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
-                 if is_unit_expr(expr) && !expr.span.from_expansion() {
-                     span_lint_and_sugg(
-                         cx,
-                         UNUSED_UNIT,
-                         expr.span,
-                         "unneeded `()`",
-                         "remove the `()`",
-                         String::new(),
-                         Applicability::MachineApplicable,
-                     );
-                 }
++                    NEEDLESS_RETURN,
++                    ret_span,
++                    "unneeded `return` statement",
++                    "remove `return`",
 +                    String::new(),
 +                    Applicability::MachineApplicable,
 +                );
-             _ => (),
-         }
-     }
-     fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
-         let segments = &poly.trait_ref.path.segments;
-         if_chain! {
-             if segments.len() == 1;
-             if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str());
-             if let Some(args) = &segments[0].args;
-             if let ast::GenericArgs::Parenthesized(generic_args) = &**args;
-             if let ast::FnRetTy::Ty(ty) = &generic_args.output;
-             if ty.kind.is_unit();
-             then {
-                 lint_unneeded_unit_return(cx, ty, generic_args.span);
-             }
-         }
 +            },
- fn attr_is_cfg(attr: &ast::Attribute) -> bool {
-     attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
++            RetReplacement::Block => {
++                span_lint_and_sugg(
++                    cx,
++                    NEEDLESS_RETURN,
++                    ret_span,
++                    "unneeded `return` statement",
++                    "replace `return` with an empty block",
++                    "{}".to_string(),
++                    Applicability::MachineApplicable,
++                );
++            },
++        },
 +    }
 +}
 +
- // get the def site
- #[must_use]
- fn get_def(span: Span) -> Option<Span> {
-     if span.from_expansion() {
-         Some(span.ctxt().outer_expn_data().def_site)
-     } else {
-         None
-     }
++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
 +}
 +
- // is this expr a `()` unit?
- fn is_unit_expr(expr: &ast::Expr) -> bool {
-     if let ast::ExprKind::Tup(ref vals) = expr.kind {
-         vals.is_empty()
-     } else {
-         false
++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()
++                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
++        }
++
++        walk_expr(self, expr);
 +    }
- fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
-     let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
-         fn_source
-             .rfind("->")
-             .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
-                 (
-                     #[allow(clippy::cast_possible_truncation)]
-                     ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
-                     Applicability::MachineApplicable,
-                 )
-             })
-     } else {
-         (ty.span, Applicability::MaybeIncorrect)
-     };
-     span_lint_and_sugg(
-         cx,
-         UNUSED_UNIT,
-         ret_span,
-         "unneeded unit return type",
-         "remove the `-> ()`",
-         String::new(),
-         appl,
-     );
 +
++    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
++        NestedVisitorMap::None
++    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e096c9aebc122fe8b7a53ef15d446fce2512d442
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,51 @@@
++use crate::utils::{eq_expr_value, snippet, span_lint};
++use rustc_hir::{Expr, ExprKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++
++declare_clippy_lint! {
++    /// **What it does:** Checks for explicit self-assignments.
++    ///
++    /// **Why is this bad?** Self-assignments are redundant and unlikely to be
++    /// intentional.
++    ///
++    /// **Known problems:** If expression contains any deref coercions or
++    /// indexing operations they are assumed not to have any side effects.
++    ///
++    /// **Example:**
++    ///
++    /// ```rust
++    /// struct Event {
++    ///     id: usize,
++    ///     x: i32,
++    ///     y: i32,
++    /// }
++    ///
++    /// fn copy_position(a: &mut Event, b: &Event) {
++    ///     a.x = b.x;
++    ///     a.y = a.y;
++    /// }
++    /// ```
++    pub SELF_ASSIGNMENT,
++    correctness,
++    "explicit self-assignment"
++}
++
++declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]);
++
++impl<'tcx> LateLintPass<'tcx> for SelfAssignment {
++    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
++        if let ExprKind::Assign(lhs, rhs, _) = &expr.kind {
++            if eq_expr_value(cx, lhs, rhs) {
++                let lhs = snippet(cx, lhs.span, "<lhs>");
++                let rhs = snippet(cx, rhs.span, "<rhs>");
++                span_lint(
++                    cx,
++                    SELF_ASSIGNMENT,
++                    expr.span,
++                    &format!("self-assignment of `{}` to `{}`", rhs, lhs),
++                );
++            }
++        }
++    }
++}
index cd7056620a2e02c19744a17b42e0b129bb9bbc8a,0000000000000000000000000000000000000000..99e4b293ac6809b40e74b2a33b62db8fa41e72ca
mode 100644,000000..100644
--- /dev/null
@@@ -1,130 -1,0 +1,132 @@@
-         if is_slice_of_primitives(cx, slice);
 +use crate::utils::{is_slice_of_primitives, span_lint_and_sugg, sugg::Sugg};
 +
 +use if_chain::if_chain;
 +
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:**
 +    /// When sorting primitive values (integers, bools, chars, as well
 +    /// as arrays, slices, and tuples of such items), it is better to
 +    /// use an unstable sort than a stable sort.
 +    ///
 +    /// **Why is this bad?**
 +    /// Using a stable sort consumes more memory and cpu cycles. Because
 +    /// values which compare equal are identical, preserving their
 +    /// relative order (the guarantee that a stable sort provides) means
 +    /// nothing, while the extra costs still apply.
 +    ///
 +    /// **Known problems:**
 +    /// None
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// let mut vec = vec![2, 1, 3];
 +    /// vec.sort();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let mut vec = vec![2, 1, 3];
 +    /// vec.sort_unstable();
 +    /// ```
 +    pub STABLE_SORT_PRIMITIVE,
 +    perf,
 +    "use of sort() when sort_unstable() is equivalent"
 +}
 +
 +declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]);
 +
 +/// The three "kinds" of sorts
 +enum SortingKind {
 +    Vanilla,
 +    /* The other kinds of lint are currently commented out because they
 +     * can map distinct values to equal ones. If the key function is
 +     * provably one-to-one, or if the Cmp function conserves equality,
 +     * then they could be linted on, but I don't know if we can check
 +     * for that. */
 +
 +    /* ByKey,
 +     * ByCmp, */
 +}
 +impl SortingKind {
 +    /// The name of the stable version of this kind of sort
 +    fn stable_name(&self) -> &str {
 +        match self {
 +            SortingKind::Vanilla => "sort",
 +            /* SortingKind::ByKey => "sort_by_key",
 +             * SortingKind::ByCmp => "sort_by", */
 +        }
 +    }
 +    /// The name of the unstable version of this kind of sort
 +    fn unstable_name(&self) -> &str {
 +        match self {
 +            SortingKind::Vanilla => "sort_unstable",
 +            /* SortingKind::ByKey => "sort_unstable_by_key",
 +             * SortingKind::ByCmp => "sort_unstable_by", */
 +        }
 +    }
 +    /// Takes the name of a function call and returns the kind of sort
 +    /// that corresponds to that function name (or None if it isn't)
 +    fn from_stable_name(name: &str) -> Option<SortingKind> {
 +        match name {
 +            "sort" => Some(SortingKind::Vanilla),
 +            // "sort_by" => Some(SortingKind::ByCmp),
 +            // "sort_by_key" => Some(SortingKind::ByKey),
 +            _ => None,
 +        }
 +    }
 +}
 +
 +/// A detected instance of this lint
 +struct LintDetection {
 +    slice_name: String,
 +    method: SortingKind,
 +    method_args: String,
++    slice_type: String,
 +}
 +
 +fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
 +    if_chain! {
 +        if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
 +        if let Some(slice) = &args.get(0);
 +        if let Some(method) = SortingKind::from_stable_name(&method_name.ident.name.as_str());
-             Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str })
++        if let Some(slice_type) = is_slice_of_primitives(cx, slice);
 +        then {
 +            let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
-                     "Use {} instead of {}",
++            Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl LateLintPass<'_> for StableSortPrimitive {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
 +            span_lint_and_sugg(
 +                cx,
 +                STABLE_SORT_PRIMITIVE,
 +                expr.span,
 +                format!(
-                     detection.method.stable_name()
++                    "used {} instead of {} to sort primitive type `{}`",
++                    detection.method.stable_name(),
 +                    detection.method.unstable_name(),
++                    detection.slice_type,
 +                )
 +                .as_str(),
 +                "try",
 +                format!(
 +                    "{}.{}({})",
 +                    detection.slice_name,
 +                    detection.method.unstable_name(),
 +                    detection.method_args
 +                ),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
index 4e335a0222f2067c3fd33e05f9bed56c5fa91bff,0000000000000000000000000000000000000000..3a688a7bbef324cd12a61086ec78fa9d059230ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,208 @@@
-                 &["Add", "Sub", "Mul", "Div"],
 +use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g.
 +    /// subtracting elements in an Add impl.
 +    ///
 +    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// impl Add for Foo {
 +    ///     type Output = Foo;
 +    ///
 +    ///     fn add(self, other: Foo) -> Foo {
 +    ///         Foo(self.0 - other.0)
 +    ///     }
 +    /// }
 +    /// ```
 +    pub SUSPICIOUS_ARITHMETIC_IMPL,
 +    correctness,
 +    "suspicious use of operators in impl of arithmetic trait"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g.
 +    /// subtracting elements in an AddAssign impl.
 +    ///
 +    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// impl AddAssign for Foo {
 +    ///     fn add_assign(&mut self, other: Foo) {
 +    ///         *self = *self - other;
 +    ///     }
 +    /// }
 +    /// ```
 +    pub SUSPICIOUS_OP_ASSIGN_IMPL,
 +    correctness,
 +    "suspicious use of operators in impl of OpAssign trait"
 +}
 +
 +declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]);
 +
 +impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind {
 +            match binop.node {
 +                hir::BinOpKind::Eq
 +                | hir::BinOpKind::Lt
 +                | hir::BinOpKind::Le
 +                | hir::BinOpKind::Ne
 +                | hir::BinOpKind::Ge
 +                | hir::BinOpKind::Gt => return,
 +                _ => {},
 +            }
 +
 +            // Check for more than one binary operation in the implemented function
 +            // Linting when multiple operations are involved can result in false positives
 +            if_chain! {
 +                let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
 +                if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn);
 +                if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
 +                let body = cx.tcx.hir().body(body_id);
 +                let mut visitor = BinaryExprVisitor { nb_binops: 0 };
 +
 +                then {
 +                    walk_expr(&mut visitor, &body.value);
 +                    if visitor.nb_binops > 1 {
 +                        return;
 +                    }
 +                }
 +            }
 +
 +            if let Some(impl_trait) = check_binop(
 +                cx,
 +                expr,
 +                binop.node,
++                &[
++                    "Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor", "Shl", "Shr",
++                ],
 +                &[
 +                    hir::BinOpKind::Add,
 +                    hir::BinOpKind::Sub,
 +                    hir::BinOpKind::Mul,
 +                    hir::BinOpKind::Div,
++                    hir::BinOpKind::Rem,
++                    hir::BinOpKind::BitAnd,
++                    hir::BinOpKind::BitOr,
++                    hir::BinOpKind::BitXor,
++                    hir::BinOpKind::Shl,
++                    hir::BinOpKind::Shr,
 +                ],
 +            ) {
 +                span_lint(
 +                    cx,
 +                    SUSPICIOUS_ARITHMETIC_IMPL,
 +                    binop.span,
 +                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
 +                );
 +            }
 +
 +            if let Some(impl_trait) = check_binop(
 +                cx,
 +                expr,
 +                binop.node,
 +                &[
 +                    "AddAssign",
 +                    "SubAssign",
 +                    "MulAssign",
 +                    "DivAssign",
 +                    "BitAndAssign",
 +                    "BitOrAssign",
 +                    "BitXorAssign",
 +                    "RemAssign",
 +                    "ShlAssign",
 +                    "ShrAssign",
 +                ],
 +                &[
 +                    hir::BinOpKind::Add,
 +                    hir::BinOpKind::Sub,
 +                    hir::BinOpKind::Mul,
 +                    hir::BinOpKind::Div,
 +                    hir::BinOpKind::BitAnd,
 +                    hir::BinOpKind::BitOr,
 +                    hir::BinOpKind::BitXor,
 +                    hir::BinOpKind::Rem,
 +                    hir::BinOpKind::Shl,
 +                    hir::BinOpKind::Shr,
 +                ],
 +            ) {
 +                span_lint(
 +                    cx,
 +                    SUSPICIOUS_OP_ASSIGN_IMPL,
 +                    binop.span,
 +                    &format!("suspicious use of binary operator in `{}` impl", impl_trait),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_binop(
 +    cx: &LateContext<'_>,
 +    expr: &hir::Expr<'_>,
 +    binop: hir::BinOpKind,
 +    traits: &[&'static str],
 +    expected_ops: &[hir::BinOpKind],
 +) -> Option<&'static str> {
 +    let mut trait_ids = vec![];
 +    let [krate, module] = crate::utils::paths::OPS_MODULE;
 +
 +    for &t in traits {
 +        let path = [krate, module, t];
 +        if let Some(trait_id) = get_trait_def_id(cx, &path) {
 +            trait_ids.push(trait_id);
 +        } else {
 +            return None;
 +        }
 +    }
 +
 +    // Get the actually implemented trait
 +    let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
 +
 +    if_chain! {
 +        if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
 +        if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.res.def_id());
 +        if binop != expected_ops[idx];
 +        then{
 +            return Some(traits[idx])
 +        }
 +    }
 +
 +    None
 +}
 +
 +struct BinaryExprVisitor {
 +    nb_binops: u32,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +        match expr.kind {
 +            hir::ExprKind::Binary(..)
 +            | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
 +            | hir::ExprKind::AssignOp(..) => self.nb_binops += 1,
 +            _ => {},
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index 754f87e6b55e2585f9b79b4c7993e78b6049df21,0000000000000000000000000000000000000000..cc39f060fc7f3929a69ed1860ca789a6dfbc6e54
mode 100644,000000..100644
--- /dev/null
@@@ -1,263 -1,0 +1,263 @@@
-     differing_macro_contexts, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty,
-     SpanlessEq,
 +use crate::utils::sugg::Sugg;
 +use crate::utils::{
-             if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
-             if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
++    differing_macro_contexts, eq_expr_value, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_then,
++    walk_ptrs_ty,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for manual swapping.
 +    ///
 +    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
 +    /// without deinitializing or copying either variable.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let mut a = 42;
 +    /// let mut b = 1337;
 +    ///
 +    /// let t = b;
 +    /// b = a;
 +    /// a = t;
 +    /// ```
 +    /// Use std::mem::swap():
 +    /// ```rust
 +    /// let mut a = 1;
 +    /// let mut b = 2;
 +    /// std::mem::swap(&mut a, &mut b);
 +    /// ```
 +    pub MANUAL_SWAP,
 +    complexity,
 +    "manual swap of two variables"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
 +    ///
 +    /// **Why is this bad?** This looks like a failed attempt to swap.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let mut a = 1;
 +    /// # let mut b = 2;
 +    /// a = b;
 +    /// b = a;
 +    /// ```
 +    /// If swapping is intended, use `swap()` instead:
 +    /// ```rust
 +    /// # let mut a = 1;
 +    /// # let mut b = 2;
 +    /// std::mem::swap(&mut a, &mut b);
 +    /// ```
 +    pub ALMOST_SWAPPED,
 +    correctness,
 +    "`foo = bar; bar = foo` sequence"
 +}
 +
 +declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Swap {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
 +        check_manual_swap(cx, block);
 +        check_suspicious_swap(cx, block);
 +    }
 +}
 +
 +/// Implementation of the `MANUAL_SWAP` lint.
 +fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
 +    for w in block.stmts.windows(3) {
 +        if_chain! {
 +            // let t = foo();
 +            if let StmtKind::Local(ref tmp) = w[0].kind;
 +            if let Some(ref tmp_init) = tmp.init;
 +            if let PatKind::Binding(.., ident, None) = tmp.pat.kind;
 +
 +            // foo() = bar();
 +            if let StmtKind::Semi(ref first) = w[1].kind;
 +            if let ExprKind::Assign(ref lhs1, ref rhs1, _) = first.kind;
 +
 +            // bar() = t;
 +            if let StmtKind::Semi(ref second) = w[2].kind;
 +            if let ExprKind::Assign(ref lhs2, ref rhs2, _) = second.kind;
 +            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind;
 +            if rhs2.segments.len() == 1;
 +
 +            if ident.as_str() == rhs2.segments[0].ident.as_str();
-             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
++            if eq_expr_value(cx, tmp_init, lhs1);
++            if eq_expr_value(cx, rhs1, lhs2);
 +            then {
 +                if let ExprKind::Field(ref lhs1, _) = lhs1.kind {
 +                    if let ExprKind::Field(ref lhs2, _) = lhs2.kind {
 +                        if lhs1.hir_id.owner == lhs2.hir_id.owner {
 +                            return;
 +                        }
 +                    }
 +                }
 +
 +                let mut applicability = Applicability::MachineApplicable;
 +
 +                let slice = check_for_slice(cx, lhs1, lhs2);
 +                let (replace, what, sugg) = if let Slice::NotSwappable = slice {
 +                    return;
 +                } else if let Slice::Swappable(slice, idx1, idx2) = slice {
 +                    if let Some(slice) = Sugg::hir_opt(cx, slice) {
 +                        (
 +                            false,
 +                            format!(" elements of `{}`", slice),
 +                            format!(
 +                                "{}.swap({}, {})",
 +                                slice.maybe_par(),
 +                                snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
 +                                snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
 +                            ),
 +                        )
 +                    } else {
 +                        (false, String::new(), String::new())
 +                    }
 +                } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
 +                    (
 +                        true,
 +                        format!(" `{}` and `{}`", first, second),
 +                        format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
 +                    )
 +                } else {
 +                    (true, String::new(), String::new())
 +                };
 +
 +                let span = w[0].span.to(second.span);
 +
 +                span_lint_and_then(
 +                    cx,
 +                    MANUAL_SWAP,
 +                    span,
 +                    &format!("this looks like you are swapping{} manually", what),
 +                    |diag| {
 +                        if !sugg.is_empty() {
 +                            diag.span_suggestion(
 +                                span,
 +                                "try",
 +                                sugg,
 +                                applicability,
 +                            );
 +
 +                            if replace {
 +                                diag.note("or maybe you should use `std::mem::replace`?");
 +                            }
 +                        }
 +                    }
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +enum Slice<'a> {
 +    /// `slice.swap(idx1, idx2)` can be used
 +    ///
 +    /// ## Example
 +    ///
 +    /// ```rust
 +    /// # let mut a = vec![0, 1];
 +    /// let t = a[1];
 +    /// a[1] = a[0];
 +    /// a[0] = t;
 +    /// // can be written as
 +    /// a.swap(0, 1);
 +    /// ```
 +    Swappable(&'a Expr<'a>, &'a Expr<'a>, &'a Expr<'a>),
 +    /// The `swap` function cannot be used.
 +    ///
 +    /// ## Example
 +    ///
 +    /// ```rust
 +    /// # let mut a = [vec![1, 2], vec![3, 4]];
 +    /// let t = a[0][1];
 +    /// a[0][1] = a[1][0];
 +    /// a[1][0] = t;
 +    /// ```
 +    NotSwappable,
 +    /// Not a slice
 +    None,
 +}
 +
 +/// Checks if both expressions are index operations into "slice-like" types.
 +fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> {
 +    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
 +        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
-             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
-             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
++            if eq_expr_value(cx, lhs1, lhs2) {
 +                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
 +
 +                if matches!(ty.kind, ty::Slice(_))
 +                    || matches!(ty.kind, ty::Array(_, _))
 +                    || is_type_diagnostic_item(cx, ty, sym!(vec_type))
 +                    || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
 +                {
 +                    return Slice::Swappable(lhs1, idx1, idx2);
 +                }
 +            } else {
 +                return Slice::NotSwappable;
 +            }
 +        }
 +    }
 +
 +    Slice::None
 +}
 +
 +/// Implementation of the `ALMOST_SWAPPED` lint.
 +fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
 +    for w in block.stmts.windows(2) {
 +        if_chain! {
 +            if let StmtKind::Semi(ref first) = w[0].kind;
 +            if let StmtKind::Semi(ref second) = w[1].kind;
 +            if !differing_macro_contexts(first.span, second.span);
 +            if let ExprKind::Assign(ref lhs0, ref rhs0, _) = first.kind;
 +            if let ExprKind::Assign(ref lhs1, ref rhs1, _) = second.kind;
++            if eq_expr_value(cx, lhs0, rhs1);
++            if eq_expr_value(cx, lhs1, rhs0);
 +            then {
 +                let lhs0 = Sugg::hir_opt(cx, lhs0);
 +                let rhs0 = Sugg::hir_opt(cx, rhs0);
 +                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
 +                    (
 +                        format!(" `{}` and `{}`", first, second),
 +                        first.mut_addr().to_string(),
 +                        second.mut_addr().to_string(),
 +                    )
 +                } else {
 +                    (String::new(), String::new(), String::new())
 +                };
 +
 +                let span = first.span.to(second.span);
 +
 +                span_lint_and_then(cx,
 +                                   ALMOST_SWAPPED,
 +                                   span,
 +                                   &format!("this looks like you are trying to swap{}", what),
 +                                   |diag| {
 +                                       if !what.is_empty() {
 +                                           diag.span_suggestion(
 +                                               span,
 +                                               "try",
 +                                               format!(
 +                                                   "std::mem::swap({}, {})",
 +                                                   lhs,
 +                                                   rhs,
 +                                               ),
 +                                               Applicability::MaybeIncorrect,
 +                                           );
 +                                           diag.note("or maybe you should use `std::mem::replace`?");
 +                                       }
 +                                   });
 +            }
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..006d7a3a12d9ae56d06f0774abc75532d97f095f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,122 @@@
++use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint};
++use if_chain::if_chain;
++use rustc_hir::def::Res;
++use rustc_hir::{Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_tool_lint, impl_lint_pass};
++
++declare_clippy_lint! {
++    /// **What it does:** Checks for uses of `to_string()` in `Display` traits.
++    ///
++    /// **Why is this bad?** Usually `to_string` is implemented indirectly
++    /// via `Display`. Hence using it while implementing `Display` would
++    /// lead to infinite recursion.
++    ///
++    /// **Known problems:** None.
++    ///
++    /// **Example:**
++    ///
++    /// ```rust
++    /// use std::fmt;
++    ///
++    /// struct Structure(i32);
++    /// impl fmt::Display for Structure {
++    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++    ///         write!(f, "{}", self.to_string())
++    ///     }
++    /// }
++    ///
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// use std::fmt;
++    ///
++    /// struct Structure(i32);
++    /// impl fmt::Display for Structure {
++    ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++    ///         write!(f, "{}", self.0)
++    ///     }
++    /// }
++    /// ```
++    pub TO_STRING_IN_DISPLAY,
++    correctness,
++    "`to_string` method used while implementing `Display` trait"
++}
++
++#[derive(Default)]
++pub struct ToStringInDisplay {
++    in_display_impl: bool,
++    self_hir_id: Option<HirId>,
++}
++
++impl ToStringInDisplay {
++    pub fn new() -> Self {
++        Self {
++            in_display_impl: false,
++            self_hir_id: None,
++        }
++    }
++}
++
++impl_lint_pass!(ToStringInDisplay => [TO_STRING_IN_DISPLAY]);
++
++impl LateLintPass<'_> for ToStringInDisplay {
++    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
++        if is_display_impl(cx, item) {
++            self.in_display_impl = true;
++        }
++    }
++
++    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
++        if is_display_impl(cx, item) {
++            self.in_display_impl = false;
++            self.self_hir_id = None;
++        }
++    }
++
++    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
++        if_chain! {
++            if self.in_display_impl;
++            if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
++            let body = cx.tcx.hir().body(*body_id);
++            if !body.params.is_empty();
++            then {
++                let self_param = &body.params[0];
++                self.self_hir_id = Some(self_param.pat.hir_id);
++            }
++        }
++    }
++
++    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
++        if_chain! {
++            if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind;
++            if path.ident.name == sym!(to_string);
++            if match_trait_method(cx, expr, &paths::TO_STRING);
++            if self.in_display_impl;
++            if let ExprKind::Path(ref qpath) = args[0].kind;
++            if let Res::Local(hir_id) = qpath_res(cx, qpath, args[0].hir_id);
++            if let Some(self_hir_id) = self.self_hir_id;
++            if hir_id == self_hir_id;
++            then {
++                span_lint(
++                    cx,
++                    TO_STRING_IN_DISPLAY,
++                    expr.span,
++                    "using `to_string` in `fmt::Display` implementation might lead to infinite recursion",
++                );
++            }
++        }
++    }
++}
++
++fn is_display_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
++    if_chain! {
++        if let ItemKind::Impl { of_trait: Some(trait_ref), .. } = &item.kind;
++        if let Some(did) = trait_ref.trait_def_id();
++        then {
++            match_def_path(cx, did, &paths::DISPLAY_TRAIT)
++        } else {
++            false
++        }
++    }
++}
index 28fd55f6ff0ad0ea2fbe4e84a913f9ee39b78ec1,0000000000000000000000000000000000000000..50d9c93f9d405f16e956de1c6446fada39ea7b75
mode 100644,000000..100644
--- /dev/null
@@@ -1,753 -1,0 +1,757 @@@
-     is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg,
 +use crate::utils::{
-                     (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then(
++    in_constant, is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_sugg,
 +    span_lint_and_then, sugg,
 +};
 +use if_chain::if_chain;
 +use rustc_ast as ast;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, TyKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, cast::CastKind, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::DUMMY_SP;
 +use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
 +use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes that can't ever be correct on any
 +    /// architecture.
 +    ///
 +    /// **Why is this bad?** It's basically guaranteed to be undefined behaviour.
 +    ///
 +    /// **Known problems:** When accessing C, users might want to store pointer
 +    /// sized objects in `extradata` arguments to save an allocation.
 +    ///
 +    /// **Example:**
 +    /// ```ignore
 +    /// let ptr: *const T = core::intrinsics::transmute('x')
 +    /// ```
 +    pub WRONG_TRANSMUTE,
 +    correctness,
 +    "transmutes that are confusing at best, undefined behaviour at worst and always useless"
 +}
 +
 +// FIXME: Move this to `complexity` again, after #5343 is fixed
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes to the original type of the object
 +    /// and transmutes that could be a cast.
 +    ///
 +    /// **Why is this bad?** Readability. The code tricks people into thinking that
 +    /// something complex is going on.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
 +    /// ```
 +    pub USELESS_TRANSMUTE,
 +    nursery,
 +    "transmutes that have the same to and from types or could be a cast/coercion"
 +}
 +
 +// FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery.
 +declare_clippy_lint! {
 +    /// **What it does:**Checks for transmutes that could be a pointer cast.
 +    ///
 +    /// **Why is this bad?** Readability. The code tricks people into thinking that
 +    /// something complex is going on.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// # let p: *const [i32] = &[];
 +    /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let p: *const [i32] = &[];
 +    /// p as *const [u16];
 +    /// ```
 +    pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    complexity,
 +    "transmutes that could be a pointer cast"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes between a type `T` and `*T`.
 +    ///
 +    /// **Why is this bad?** It's easy to mistakenly transmute between a type and a
 +    /// pointer to that type.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// core::intrinsics::transmute(t) // where the result type is the same as
 +    ///                                // `*t` or `&t`'s
 +    /// ```
 +    pub CROSSPOINTER_TRANSMUTE,
 +    complexity,
 +    "transmutes that have to or from types that are a pointer to the other"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from a pointer to a reference.
 +    ///
 +    /// **Why is this bad?** This can always be rewritten with `&` and `*`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// unsafe {
 +    ///     let _: &T = std::mem::transmute(p); // where p: *const T
 +    /// }
 +    ///
 +    /// // can be written:
 +    /// let _: &T = &*p;
 +    /// ```
 +    pub TRANSMUTE_PTR_TO_REF,
 +    complexity,
 +    "transmutes from a pointer to a reference type"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from an integer to a `char`.
 +    ///
 +    /// **Why is this bad?** Not every integer is a Unicode scalar value.
 +    ///
 +    /// **Known problems:**
 +    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
 +    /// as it needs to validate the input.
 +    /// If you are certain that the input is always a valid Unicode scalar value,
 +    /// use [`from_u32_unchecked`] which is as fast as `transmute`
 +    /// but has a semantically meaningful name.
 +    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
 +    ///
 +    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
 +    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = 1_u32;
 +    /// unsafe {
 +    ///     let _: char = std::mem::transmute(x); // where x: u32
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _ = std::char::from_u32(x).unwrap();
 +    /// ```
 +    pub TRANSMUTE_INT_TO_CHAR,
 +    complexity,
 +    "transmutes from an integer to a `char`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from a `&[u8]` to a `&str`.
 +    ///
 +    /// **Why is this bad?** Not every byte slice is a valid UTF-8 string.
 +    ///
 +    /// **Known problems:**
 +    /// - [`from_utf8`] which this lint suggests using is slower than `transmute`
 +    /// as it needs to validate the input.
 +    /// If you are certain that the input is always a valid UTF-8,
 +    /// use [`from_utf8_unchecked`] which is as fast as `transmute`
 +    /// but has a semantically meaningful name.
 +    /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
 +    ///
 +    /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
 +    /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let b: &[u8] = &[1_u8, 2_u8];
 +    /// unsafe {
 +    ///     let _: &str = std::mem::transmute(b); // where b: &[u8]
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _ = std::str::from_utf8(b).unwrap();
 +    /// ```
 +    pub TRANSMUTE_BYTES_TO_STR,
 +    complexity,
 +    "transmutes from a `&[u8]` to a `&str`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from an integer to a `bool`.
 +    ///
 +    /// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = 1_u8;
 +    /// unsafe {
 +    ///     let _: bool = std::mem::transmute(x); // where x: u8
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: bool = x != 0;
 +    /// ```
 +    pub TRANSMUTE_INT_TO_BOOL,
 +    complexity,
 +    "transmutes from an integer to a `bool`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from an integer to a float.
 +    ///
 +    /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
 +    /// and safe.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// unsafe {
 +    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: f32 = f32::from_bits(1_u32);
 +    /// ```
 +    pub TRANSMUTE_INT_TO_FLOAT,
 +    complexity,
 +    "transmutes from an integer to a float"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from a float to an integer.
 +    ///
 +    /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
 +    /// and safe.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// unsafe {
 +    ///     let _: u32 = std::mem::transmute(1f32);
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: u32 = 1f32.to_bits();
 +    /// ```
 +    pub TRANSMUTE_FLOAT_TO_INT,
 +    complexity,
 +    "transmutes from a float to an integer"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes from a pointer to a pointer, or
 +    /// from a reference to a reference.
 +    ///
 +    /// **Why is this bad?** Transmutes are dangerous, and these can instead be
 +    /// written as casts.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let ptr = &1u32 as *const u32;
 +    /// unsafe {
 +    ///     // pointer-to-pointer transmute
 +    ///     let _: *const f32 = std::mem::transmute(ptr);
 +    ///     // ref-ref transmute
 +    ///     let _: &f32 = std::mem::transmute(&1u32);
 +    /// }
 +    /// // These can be respectively written:
 +    /// let _ = ptr as *const f32;
 +    /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
 +    /// ```
 +    pub TRANSMUTE_PTR_TO_PTR,
 +    complexity,
 +    "transmutes from a pointer to a pointer / a reference to a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for transmutes between collections whose
 +    /// types have different ABI, size or alignment.
 +    ///
 +    /// **Why is this bad?** This is undefined behavior.
 +    ///
 +    /// **Known problems:** Currently, we cannot know whether a type is a
 +    /// collection, so we just lint the ones that come with `std`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// // different size, therefore likely out-of-bounds memory access
 +    /// // You absolutely do not want this in your code!
 +    /// unsafe {
 +    ///     std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
 +    /// };
 +    /// ```
 +    ///
 +    /// You must always iterate, map and collect the values:
 +    ///
 +    /// ```rust
 +    /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
 +    /// ```
 +    pub UNSOUND_COLLECTION_TRANSMUTE,
 +    correctness,
 +    "transmute between collections of layout-incompatible types"
 +}
 +
 +declare_lint_pass!(Transmute => [
 +    CROSSPOINTER_TRANSMUTE,
 +    TRANSMUTE_PTR_TO_REF,
 +    TRANSMUTE_PTR_TO_PTR,
 +    USELESS_TRANSMUTE,
 +    WRONG_TRANSMUTE,
 +    TRANSMUTE_INT_TO_CHAR,
 +    TRANSMUTE_BYTES_TO_STR,
 +    TRANSMUTE_INT_TO_BOOL,
 +    TRANSMUTE_INT_TO_FLOAT,
 +    TRANSMUTE_FLOAT_TO_INT,
 +    UNSOUND_COLLECTION_TRANSMUTE,
 +    TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +]);
 +
 +// used to check for UNSOUND_COLLECTION_TRANSMUTE
 +static COLLECTIONS: &[&[&str]] = &[
 +    &paths::VEC,
 +    &paths::VEC_DEQUE,
 +    &paths::BINARY_HEAP,
 +    &paths::BTREESET,
 +    &paths::BTREEMAP,
 +    &paths::HASHSET,
 +    &paths::HASHMAP,
 +];
 +impl<'tcx> LateLintPass<'tcx> for Transmute {
 +    #[allow(clippy::similar_names, clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(ref path_expr, ref args) = e.kind;
 +            if let ExprKind::Path(ref qpath) = path_expr.kind;
 +            if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
 +            if match_def_path(cx, def_id, &paths::TRANSMUTE);
 +            then {
++                // Avoid suggesting from/to bits in const contexts.
++                // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
++                let const_context = in_constant(cx, e.hir_id);
++
 +                let from_ty = cx.typeck_results().expr_ty(&args[0]);
 +                let to_ty = cx.typeck_results().expr_ty(e);
 +
 +                match (&from_ty.kind, &to_ty.kind) {
 +                    _ if from_ty == to_ty => span_lint(
 +                        cx,
 +                        USELESS_TRANSMUTE,
 +                        e.span,
 +                        &format!("transmute from a type (`{}`) to itself", from_ty),
 +                    ),
 +                    (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => span_lint_and_then(
 +                        cx,
 +                        USELESS_TRANSMUTE,
 +                        e.span,
 +                        "transmute from a reference to a pointer",
 +                        |diag| {
 +                            if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
 +                                let rty_and_mut = ty::TypeAndMut {
 +                                    ty: rty,
 +                                    mutbl: *rty_mutbl,
 +                                };
 +
 +                                let sugg = if *ptr_ty == rty_and_mut {
 +                                    arg.as_ty(to_ty)
 +                                } else {
 +                                    arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
 +                                };
 +
 +                                diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
 +                            }
 +                        },
 +                    ),
 +                    (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => span_lint_and_then(
 +                        cx,
 +                        USELESS_TRANSMUTE,
 +                        e.span,
 +                        "transmute from an integer to a pointer",
 +                        |diag| {
 +                            if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
 +                                diag.span_suggestion(
 +                                    e.span,
 +                                    "try",
 +                                    arg.as_ty(&to_ty.to_string()).to_string(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    ),
 +                    (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => span_lint(
 +                        cx,
 +                        WRONG_TRANSMUTE,
 +                        e.span,
 +                        &format!("transmute from a `{}` to a pointer", from_ty),
 +                    ),
 +                    (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
 +                        cx,
 +                        CROSSPOINTER_TRANSMUTE,
 +                        e.span,
 +                        &format!(
 +                            "transmute from a type (`{}`) to the type that it points to (`{}`)",
 +                            from_ty, to_ty
 +                        ),
 +                    ),
 +                    (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
 +                        cx,
 +                        CROSSPOINTER_TRANSMUTE,
 +                        e.span,
 +                        &format!(
 +                            "transmute from a type (`{}`) to a pointer to that type (`{}`)",
 +                            from_ty, to_ty
 +                        ),
 +                    ),
 +                    (ty::RawPtr(from_pty), ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then(
 +                        cx,
 +                        TRANSMUTE_PTR_TO_REF,
 +                        e.span,
 +                        &format!(
 +                            "transmute from a pointer type (`{}`) to a reference type \
 +                             (`{}`)",
 +                            from_ty, to_ty
 +                        ),
 +                        |diag| {
 +                            let arg = sugg::Sugg::hir(cx, &args[0], "..");
 +                            let (deref, cast) = if *mutbl == Mutability::Mut {
 +                                ("&mut *", "*mut")
 +                            } else {
 +                                ("&*", "*const")
 +                            };
 +
 +                            let arg = if from_pty.ty == *to_ref_ty {
 +                                arg
 +                            } else {
 +                                arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty)))
 +                            };
 +
 +                            diag.span_suggestion(
 +                                e.span,
 +                                "try",
 +                                sugg::make_unop(deref, arg).to_string(),
 +                                Applicability::Unspecified,
 +                            );
 +                        },
 +                    ),
 +                    (ty::Int(ast::IntTy::I32) | ty::Uint(ast::UintTy::U32), &ty::Char) => {
 +                        span_lint_and_then(
 +                            cx,
 +                            TRANSMUTE_INT_TO_CHAR,
 +                            e.span,
 +                            &format!("transmute from a `{}` to a `char`", from_ty),
 +                            |diag| {
 +                                let arg = sugg::Sugg::hir(cx, &args[0], "..");
 +                                let arg = if let ty::Int(_) = from_ty.kind {
 +                                    arg.as_ty(ast::UintTy::U32.name_str())
 +                                } else {
 +                                    arg
 +                                };
 +                                diag.span_suggestion(
 +                                    e.span,
 +                                    "consider using",
 +                                    format!("std::char::from_u32({}).unwrap()", arg.to_string()),
 +                                    Applicability::Unspecified,
 +                                );
 +                            },
 +                        )
 +                    },
 +                    (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => {
 +                        if_chain! {
 +                            if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind);
 +                            if let ty::Uint(ast::UintTy::U8) = slice_ty.kind;
 +                            if from_mutbl == to_mutbl;
 +                            then {
 +                                let postfix = if *from_mutbl == Mutability::Mut {
 +                                    "_mut"
 +                                } else {
 +                                    ""
 +                                };
 +
 +                                span_lint_and_sugg(
 +                                    cx,
 +                                    TRANSMUTE_BYTES_TO_STR,
 +                                    e.span,
 +                                    &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
 +                                    "consider using",
 +                                    format!(
 +                                        "std::str::from_utf8{}({}).unwrap()",
 +                                        postfix,
 +                                        snippet(cx, args[0].span, ".."),
 +                                    ),
 +                                    Applicability::Unspecified,
 +                                );
 +                            } else {
 +                                if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) {
 +                                    span_lint_and_then(
 +                                        cx,
 +                                        TRANSMUTE_PTR_TO_PTR,
 +                                        e.span,
 +                                        "transmute from a reference to a reference",
 +                                        |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
 +                                            let ty_from_and_mut = ty::TypeAndMut {
 +                                                ty: ty_from,
 +                                                mutbl: *from_mutbl
 +                                            };
 +                                            let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl };
 +                                            let sugg_paren = arg
 +                                                .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
 +                                                .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
 +                                            let sugg = if *to_mutbl == Mutability::Mut {
 +                                                sugg_paren.mut_addr_deref()
 +                                            } else {
 +                                                sugg_paren.addr_deref()
 +                                            };
 +                                            diag.span_suggestion(
 +                                                e.span,
 +                                                "try",
 +                                                sugg.to_string(),
 +                                                Applicability::Unspecified,
 +                                            );
 +                                        },
 +                                    )
 +                                }
 +                            }
 +                        }
 +                    },
 +                    (ty::RawPtr(_), ty::RawPtr(to_ty)) => span_lint_and_then(
 +                        cx,
 +                        TRANSMUTE_PTR_TO_PTR,
 +                        e.span,
 +                        "transmute from a pointer to a pointer",
 +                        |diag| {
 +                            if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
 +                                let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty));
 +                                diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
 +                            }
 +                        },
 +                    ),
 +                    (ty::Int(ast::IntTy::I8) | ty::Uint(ast::UintTy::U8), ty::Bool) => {
 +                        span_lint_and_then(
 +                            cx,
 +                            TRANSMUTE_INT_TO_BOOL,
 +                            e.span,
 +                            &format!("transmute from a `{}` to a `bool`", from_ty),
 +                            |diag| {
 +                                let arg = sugg::Sugg::hir(cx, &args[0], "..");
 +                                let zero = sugg::Sugg::NonParen(Cow::from("0"));
 +                                diag.span_suggestion(
 +                                    e.span,
 +                                    "consider using",
 +                                    sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            },
 +                        )
 +                    },
-                     (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then(
++                    (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => span_lint_and_then(
 +                        cx,
 +                        TRANSMUTE_INT_TO_FLOAT,
 +                        e.span,
 +                        &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
 +                        |diag| {
 +                            let arg = sugg::Sugg::hir(cx, &args[0], "..");
 +                            let arg = if let ty::Int(int_ty) = from_ty.kind {
 +                                arg.as_ty(format!(
 +                                    "u{}",
 +                                    int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())
 +                                ))
 +                            } else {
 +                                arg
 +                            };
 +                            diag.span_suggestion(
 +                                e.span,
 +                                "consider using",
 +                                format!("{}::from_bits({})", to_ty, arg.to_string()),
 +                                Applicability::Unspecified,
 +                            );
 +                        },
 +                    ),
++                    (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => span_lint_and_then(
 +                        cx,
 +                        TRANSMUTE_FLOAT_TO_INT,
 +                        e.span,
 +                        &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
 +                        |diag| {
 +                            let mut expr = &args[0];
 +                            let mut arg = sugg::Sugg::hir(cx, expr, "..");
 +
 +                            if let ExprKind::Unary(UnOp::UnNeg, 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
 +                                let op = format!("{}{}", arg, float_ty.name_str()).into();
 +                                if let ExprKind::Lit(lit) = &expr.kind;
 +                                if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node;
 +                                then {
 +                                    match arg {
 +                                        sugg::Sugg::MaybeParen(_) => arg = sugg::Sugg::MaybeParen(op),
 +                                        _ => arg = sugg::Sugg::NonParen(op)
 +                                    }
 +                                }
 +                            }
 +
 +                            arg = sugg::Sugg::NonParen(format!("{}.to_bits()", arg.maybe_par()).into());
 +
 +                            // cast the result of `to_bits` if `to_ty` is signed
 +                            arg = if let ty::Int(int_ty) = to_ty.kind {
 +                                arg.as_ty(int_ty.name_str().to_string())
 +                            } else {
 +                                arg
 +                            };
 +
 +                            diag.span_suggestion(
 +                                e.span,
 +                                "consider using",
 +                                arg.to_string(),
 +                                Applicability::Unspecified,
 +                            );
 +                        },
 +                    ),
 +                    (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
 +                        if from_adt.did != to_adt.did ||
 +                                !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) {
 +                            return;
 +                        }
 +                        if from_substs.types().zip(to_substs.types())
 +                                              .any(|(from_ty, to_ty)| is_layout_incompatible(cx, from_ty, to_ty)) {
 +                            span_lint(
 +                                cx,
 +                                UNSOUND_COLLECTION_TRANSMUTE,
 +                                e.span,
 +                                &format!(
 +                                    "transmute from `{}` to `{}` with mismatched layout is unsound",
 +                                    from_ty,
 +                                    to_ty
 +                                )
 +                            );
 +                        }
 +                    },
 +                    (_, _) if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) => span_lint_and_then(
 +                        cx,
 +                        TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +                        e.span,
 +                        &format!(
 +                            "transmute from `{}` to `{}` which could be expressed as a pointer cast instead",
 +                            from_ty,
 +                            to_ty
 +                        ),
 +                        |diag| {
 +                            if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
 +                                let sugg = arg.as_ty(&to_ty.to_string()).to_string();
 +                                diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
 +                            }
 +                        }
 +                    ),
 +                    _ => {
 +                        return;
 +                    },
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
 +/// not available , use
 +/// the type's `ToString` implementation. In weird cases it could lead to types
 +/// with invalid `'_`
 +/// lifetime, but it should be rare.
 +fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String {
 +    let seg = last_path_segment(path);
 +    if_chain! {
 +        if let Some(ref params) = seg.args;
 +        if !params.parenthesized;
 +        if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
 +            GenericArg::Type(ty) => Some(ty),
 +            _ => None,
 +        }).nth(1);
 +        if let TyKind::Rptr(_, ref to_ty) = to_ty.kind;
 +        then {
 +            return snippet(cx, to_ty.ty.span, &to_ref_ty.to_string()).to_string();
 +        }
 +    }
 +
 +    to_ref_ty.to_string()
 +}
 +
 +// check if the component types of the transmuted collection and the result have different ABI,
 +// size or alignment
 +fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
 +    let empty_param_env = ty::ParamEnv::empty();
 +    // check if `from` and `to` are normalizable to avoid ICE (#4968)
 +    if !(is_normalizable(cx, empty_param_env, from) && is_normalizable(cx, empty_param_env, to)) {
 +        return false;
 +    }
 +    let from_ty_layout = cx.tcx.layout_of(empty_param_env.and(from));
 +    let to_ty_layout = cx.tcx.layout_of(empty_param_env.and(to));
 +    if let (Ok(from_layout), Ok(to_layout)) = (from_ty_layout, to_ty_layout) {
 +        from_layout.size != to_layout.size || from_layout.align != to_layout.align || from_layout.abi != to_layout.abi
 +    } else {
 +        // no idea about layout, so don't lint
 +        false
 +    }
 +}
 +
 +/// Check if the type conversion can be expressed as a pointer cast, instead of
 +/// a transmute. In certain cases, including some invalid casts from array
 +/// references to pointers, this may cause additional errors to be emitted and/or
 +/// ICE error messages. This function will panic if that occurs.
 +fn can_be_expressed_as_pointer_cast<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    from_ty: Ty<'tcx>,
 +    to_ty: Ty<'tcx>,
 +) -> bool {
 +    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
 +    matches!(
 +        check_cast(cx, e, from_ty, to_ty),
 +        Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
 +    )
 +}
 +
 +/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
 +/// the cast. In certain cases, including some invalid casts from array references
 +/// to pointers, this may cause additional errors to be emitted and/or ICE error
 +/// messages. This function will panic if that occurs.
 +fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
 +    let hir_id = e.hir_id;
 +    let local_def_id = hir_id.owner;
 +
 +    Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
 +        let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
 +
 +        // If we already have errors, we can't be sure we can pointer cast.
 +        assert!(
 +            !fn_ctxt.errors_reported_since_creation(),
 +            "Newly created FnCtxt contained errors"
 +        );
 +
 +        if let Ok(check) = CastCheck::new(
 +            &fn_ctxt, e, from_ty, to_ty,
 +            // We won't show any error to the user, so we don't care what the span is here.
 +            DUMMY_SP, DUMMY_SP,
 +        ) {
 +            let res = check.do_check(&fn_ctxt);
 +
 +            // do_check's documentation says that it might return Ok and create
 +            // errors in the fcx instead of returing Err in some cases. Those cases
 +            // should be filtered out before getting here.
 +            assert!(
 +                !fn_ctxt.errors_reported_since_creation(),
 +                "`fn_ctxt` contained errors after cast check!"
 +            );
 +
 +            res.ok()
 +        } else {
 +            None
 +        }
 +    })
 +}
index 7948d99162b8116b91b6236a8f0a1d1945406b34,0000000000000000000000000000000000000000..92f42168a1eabc56dd5df476d1f5b138211dff57
mode 100644,000000..100644
--- /dev/null
@@@ -1,178 -1,0 +1,183 @@@
-                     if a.meta_item_list().is_some() && a.has_name(sym!(proc_macro_derive)) {
-                         return;
 +use std::cmp;
 +
 +use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
 +use if_chain::if_chain;
++use rustc_ast::attr;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::FnKind;
 +use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::config::Config as SessionConfig;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::Span;
 +use rustc_target::abi::LayoutOf;
 +use rustc_target::spec::abi::Abi;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for functions taking arguments by reference, where
 +    /// the argument type is `Copy` and small enough to be more efficient to always
 +    /// pass by value.
 +    ///
 +    /// **Why is this bad?** In many calling conventions instances of structs will
 +    /// be passed through registers if they fit into two or less general purpose
 +    /// registers.
 +    ///
 +    /// **Known problems:** This lint is target register size dependent, it is
 +    /// limited to 32-bit to try and reduce portability problems between 32 and
 +    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
 +    /// will be different.
 +    ///
 +    /// The configuration option `trivial_copy_size_limit` can be set to override
 +    /// this limit for a project.
 +    ///
 +    /// This lint attempts to allow passing arguments by reference if a reference
 +    /// to that argument is returned. This is implemented by comparing the lifetime
 +    /// of the argument and return value for equality. However, this can cause
 +    /// false positives in cases involving multiple lifetimes that are bounded by
 +    /// each other.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// fn foo(v: &u32) {}
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// // Better
 +    /// fn foo(v: u32) {}
 +    /// ```
 +    pub TRIVIALLY_COPY_PASS_BY_REF,
 +    pedantic,
 +    "functions taking small copyable arguments by reference"
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct TriviallyCopyPassByRef {
 +    limit: u64,
 +}
 +
 +impl<'tcx> TriviallyCopyPassByRef {
 +    pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
 +        let limit = limit.unwrap_or_else(|| {
 +            let bit_width = u64::from(target.ptr_width);
 +            // Cap the calculated bit width at 32-bits to reduce
 +            // portability problems between 32 and 64-bit targets
 +            let bit_width = cmp::min(bit_width, 32);
 +            #[allow(clippy::integer_division)]
 +            let byte_width = bit_width / 8;
 +            // Use a limit of 2 times the register byte width
 +            byte_width * 2
 +        });
 +        Self { limit }
 +    }
 +
 +    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
 +        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 +
 +        let fn_sig = cx.tcx.fn_sig(fn_def_id);
 +        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);
 +
 +        // Use lifetimes to determine if we're returning a reference to the
 +        // argument. In that case we can't switch to pass-by-value as the
 +        // argument will not live long enough.
 +        let output_lts = match fn_sig.output().kind {
 +            ty::Ref(output_lt, _, _) => vec![output_lt],
 +            ty::Adt(_, substs) => substs.regions().collect(),
 +            _ => vec![],
 +        };
 +
 +        for (input, &ty) in decl.inputs.iter().zip(fn_sig.inputs()) {
 +            // All spans generated from a proc-macro invocation are the same...
 +            match span {
 +                Some(s) if s == input.span => return,
 +                _ => (),
 +            }
 +
 +            if_chain! {
 +                if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind;
 +                if !output_lts.contains(&input_lt);
 +                if is_copy(cx, ty);
 +                if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
 +                if size <= self.limit;
 +                if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
 +                then {
 +                    let value_type = if is_self_ty(decl_ty) {
 +                        "self".into()
 +                    } else {
 +                        snippet(cx, decl_ty.span, "_").into()
 +                    };
 +                    span_lint_and_sugg(
 +                        cx,
 +                        TRIVIALLY_COPY_PASS_BY_REF,
 +                        input.span,
 +                        &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.limit),
 +                        "consider passing by value instead",
 +                        value_type,
 +                        Applicability::Unspecified,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(TriviallyCopyPassByRef => [TRIVIALLY_COPY_PASS_BY_REF]);
 +
 +impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef {
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
 +        if item.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
 +            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
 +        }
 +    }
 +
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        kind: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        _body: &'tcx Body<'_>,
 +        span: Span,
 +        hir_id: HirId,
 +    ) {
 +        if span.from_expansion() {
 +            return;
 +        }
 +
 +        match kind {
 +            FnKind::ItemFn(.., header, _, attrs) => {
 +                if header.abi != Abi::Rust {
 +                    return;
 +                }
 +                for a in attrs {
++                    if let Some(meta_items) = a.meta_item_list() {
++                        if a.has_name(sym!(proc_macro_derive))
++                            || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always)))
++                        {
++                            return;
++                        }
 +                    }
 +                }
 +            },
 +            FnKind::Method(..) => (),
 +            FnKind::Closure(..) => return,
 +        }
 +
 +        // Exclude non-inherent impls
 +        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
 +            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } |
 +                ItemKind::Trait(..))
 +            {
 +                return;
 +            }
 +        }
 +
 +        self.check_poly_fn(cx, hir_id, decl, Some(span));
 +    }
 +}
index a74104e92820a3ca7288b008edebbd46848ab3ad,0000000000000000000000000000000000000000..a4676e505b6f38e946d0e83b5fdf9a6dee9a7030
mode 100644,000000..100644
--- /dev/null
@@@ -1,186 -1,0 +1,186 @@@
-     is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
-     snippet_with_macro_callsite, span_lint_and_sugg,
 +use crate::utils::{
- use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource};
++    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
++    span_lint_and_sugg,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
++use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usages of `Err(x)?`.
 +    ///
 +    /// **Why is this bad?** The `?` operator is designed to allow calls that
 +    /// can fail to be easily chained. For example, `foo()?.bar()` or
 +    /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
 +    /// always return), it is more clear to write `return Err(x)`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// fn foo(fail: bool) -> Result<i32, String> {
 +    ///     if fail {
 +    ///       Err("failed")?;
 +    ///     }
 +    ///     Ok(0)
 +    /// }
 +    /// ```
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// fn foo(fail: bool) -> Result<i32, String> {
 +    ///     if fail {
 +    ///       return Err("failed".into());
 +    ///     }
 +    ///     Ok(0)
 +    /// }
 +    /// ```
 +    pub TRY_ERR,
 +    style,
 +    "return errors explicitly rather than hiding them behind a `?`"
 +}
 +
 +declare_lint_pass!(TryErr => [TRY_ERR]);
 +
 +impl<'tcx> LateLintPass<'tcx> for TryErr {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // Looks for a structure like this:
 +        // match ::std::ops::Try::into_result(Err(5)) {
 +        //     ::std::result::Result::Err(err) =>
 +        //         #[allow(unreachable_code)]
 +        //         return ::std::ops::Try::from_error(::std::convert::From::from(err)),
 +        //     ::std::result::Result::Ok(val) =>
 +        //         #[allow(unreachable_code)]
 +        //         val,
 +        // };
 +        if_chain! {
 +            if !in_external_macro(cx.tcx.sess, expr.span);
 +            if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
 +            if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
 +            if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
 +            if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
 +            if let Some(ref try_arg) = try_args.get(0);
 +            if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
 +            if let Some(ref err_arg) = err_args.get(0);
 +            if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
 +            if match_qpath(err_fun_path, &paths::RESULT_ERR);
 +            if let Some(return_ty) = find_return_type(cx, &expr.kind);
 +            then {
 +                let prefix;
 +                let suffix;
 +                let err_ty;
 +
 +                if let Some(ty) = result_error_type(cx, return_ty) {
 +                    prefix = "Err(";
 +                    suffix = ")";
 +                    err_ty = ty;
 +                } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
 +                    prefix = "Poll::Ready(Err(";
 +                    suffix = "))";
 +                    err_ty = ty;
 +                } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
 +                    prefix = "Poll::Ready(Some(Err(";
 +                    suffix = ")))";
 +                    err_ty = ty;
 +                } else {
 +                    return;
 +                };
 +
 +                let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
 +
 +                let origin_snippet = if err_arg.span.from_expansion() {
 +                    snippet_with_macro_callsite(cx, err_arg.span, "_")
 +                } else {
 +                    snippet(cx, err_arg.span, "_")
 +                };
 +                let suggestion = if err_ty == expr_err_ty {
 +                    format!("return {}{}{}", prefix, origin_snippet, suffix)
 +                } else {
 +                    format!("return {}{}.into(){}", prefix, origin_snippet, suffix)
 +                };
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    TRY_ERR,
 +                    expr.span,
 +                    "returning an `Err(_)` with the `?` operator",
 +                    "try this",
 +                    suggestion,
 +                    Applicability::MachineApplicable
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Finds function return type by examining return expressions in match arms.
 +fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
 +    if let ExprKind::Match(_, ref arms, MatchSource::TryDesugar) = expr {
 +        for arm in arms.iter() {
 +            if let ExprKind::Ret(Some(ref ret)) = arm.body.kind {
 +                return Some(cx.typeck_results().expr_ty(ret));
 +            }
 +        }
 +    }
 +    None
 +}
 +
 +/// Extracts the error type from Result<T, E>.
 +fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 +    if_chain! {
 +        if let ty::Adt(_, subst) = ty.kind;
 +        if is_type_diagnostic_item(cx, ty, sym!(result_type));
 +        let err_ty = subst.type_at(1);
 +        then {
 +            Some(err_ty)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// Extracts the error type from Poll<Result<T, E>>.
 +fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 +    if_chain! {
 +        if let ty::Adt(def, subst) = ty.kind;
 +        if match_def_path(cx, def.did, &paths::POLL);
 +        let ready_ty = subst.type_at(0);
 +
 +        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind;
 +        if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did);
 +        let err_ty = ready_subst.type_at(1);
 +
 +        then {
 +            Some(err_ty)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// Extracts the error type from Poll<Option<Result<T, E>>>.
 +fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 +    if_chain! {
 +        if let ty::Adt(def, subst) = ty.kind;
 +        if match_def_path(cx, def.did, &paths::POLL);
 +        let ready_ty = subst.type_at(0);
 +
 +        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind;
 +        if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did);
 +        let some_ty = ready_subst.type_at(0);
 +
 +        if let ty::Adt(some_def, some_subst) = some_ty.kind;
 +        if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did);
 +        let err_ty = some_subst.type_at(1);
 +
 +        then {
 +            Some(err_ty)
 +        } else {
 +            None
 +        }
 +    }
 +}
index 0fd70550fa0c292dfbe001a2ad3df146565d1a09,0000000000000000000000000000000000000000..7e9190bef5e78425ac5478cb78e6e2ec24879f12
mode 100644,000000..100644
--- /dev/null
@@@ -1,2604 -1,0 +1,2615 @@@
-                         if let Some(span) = match_type_parameter(cx, qpath, &paths::BOX) {
 +#![allow(rustc::default_hash_types)]
 +
 +use std::borrow::Cow;
 +use std::cmp::Ordering;
 +use std::collections::BTreeMap;
 +
 +use if_chain::if_chain;
 +use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy};
 +use rustc_errors::{Applicability, DiagnosticBuilder};
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
 +    ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn,
 +    TraitItem, TraitItemKind, TyKind, UnOp,
 +};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckResults};
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::sym;
 +use rustc_target::abi::LayoutOf;
 +use rustc_target::spec::abi::Abi;
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use crate::consts::{constant, Constant};
 +use crate::utils::paths;
 +use crate::utils::{
 +    clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item,
 +    last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral,
 +    qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability,
 +    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
 +};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
 +    ///
 +    /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
 +    /// the heap. So if you `Box` it, you just add another level of indirection
 +    /// without any benefit whatsoever.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// struct X {
 +    ///     values: Box<Vec<Foo>>,
 +    /// }
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust,ignore
 +    /// struct X {
 +    ///     values: Vec<Foo>,
 +    /// }
 +    /// ```
 +    pub BOX_VEC,
 +    perf,
 +    "usage of `Box<Vec<T>>`, vector elements are already on the heap"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
 +    ///
 +    /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
 +    /// the heap. So if you `Box` its contents, you just add another level of indirection.
 +    ///
 +    /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see #3530,
 +    /// 1st comment).
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// struct X {
 +    ///     values: Vec<Box<i32>>,
 +    /// }
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// struct X {
 +    ///     values: Vec<i32>,
 +    /// }
 +    /// ```
 +    pub VEC_BOX,
 +    complexity,
 +    "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
 +    /// definitions
 +    ///
 +    /// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
 +    /// represents an optional optional value which is logically the same thing as an optional
 +    /// value but has an unneeded extra level of wrapping.
 +    ///
 +    /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
 +    /// consider a custom `enum` instead, with clear names for each case.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example**
 +    /// ```rust
 +    /// fn get_data() -> Option<Option<u32>> {
 +    ///     None
 +    /// }
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// pub enum Contents {
 +    ///     Data(Vec<u8>), // Was Some(Some(Vec<u8>))
 +    ///     NotYetFetched, // Was Some(None)
 +    ///     None,          // Was None
 +    /// }
 +    ///
 +    /// fn get_data() -> Contents {
 +    ///     Contents::None
 +    /// }
 +    /// ```
 +    pub OPTION_OPTION,
 +    pedantic,
 +    "usage of `Option<Option<T>>`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
 +    /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
 +    ///
 +    /// **Why is this bad?** Gankro says:
 +    ///
 +    /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
 +    /// pointers and indirection.
 +    /// > It wastes memory, it has terrible cache locality, and is all-around slow.
 +    /// `RingBuf`, while
 +    /// > "only" amortized for push/pop, should be faster in the general case for
 +    /// almost every possible
 +    /// > workload, and isn't even amortized at all if you can predict the capacity
 +    /// you need.
 +    /// >
 +    /// > `LinkedList`s are only really good if you're doing a lot of merging or
 +    /// splitting of lists.
 +    /// > This is because they can just mangle some pointers instead of actually
 +    /// copying the data. Even
 +    /// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
 +    /// can still be better
 +    /// > because of how expensive it is to seek to the middle of a `LinkedList`.
 +    ///
 +    /// **Known problems:** False positives – the instances where using a
 +    /// `LinkedList` makes sense are few and far between, but they can still happen.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::collections::LinkedList;
 +    /// let x: LinkedList<usize> = LinkedList::new();
 +    /// ```
 +    pub LINKEDLIST,
 +    pedantic,
 +    "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
 +    ///
 +    /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
 +    /// general.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// fn foo(bar: &Box<T>) { ... }
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust,ignore
 +    /// fn foo(bar: &T) { ... }
 +    /// ```
 +    pub BORROWED_BOX,
 +    complexity,
 +    "a borrow of a boxed type"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of redundant allocations anywhere in the code.
 +    ///
 +    /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
 +    /// add an unnecessary level of indirection.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::rc::Rc;
 +    /// fn foo(bar: Rc<&usize>) {}
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// fn foo(bar: &usize) {}
 +    /// ```
 +    pub REDUNDANT_ALLOCATION,
 +    perf,
 +    "redundant allocation"
 +}
 +
 +pub struct Types {
 +    vec_box_size_threshold: u64,
 +}
 +
 +impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Types {
 +    fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
 +        // Skip trait implementations; see issue #605.
 +        if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
 +            if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
 +                return;
 +            }
 +        }
 +
 +        self.check_fn_decl(cx, decl);
 +    }
 +
 +    fn check_struct_field(&mut self, cx: &LateContext<'_>, field: &hir::StructField<'_>) {
 +        self.check_ty(cx, &field.ty, false);
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
 +        match item.kind {
 +            TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false),
 +            TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl),
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
 +        if let Some(ref ty) = local.ty {
 +            self.check_ty(cx, ty, true);
 +        }
 +    }
 +}
 +
 +/// Checks if `qpath` has last segment with type parameter matching `path`
 +fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str]) -> Option<Span> {
 +    let last = last_path_segment(qpath);
 +    if_chain! {
 +        if let Some(ref params) = last.args;
 +        if !params.parenthesized;
 +        if let Some(ty) = params.args.iter().find_map(|arg| match arg {
 +            GenericArg::Type(ty) => Some(ty),
 +            _ => None,
 +        });
 +        if let TyKind::Path(ref qpath) = ty.kind;
 +        if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id();
 +        if match_def_path(cx, did, path);
 +        then {
 +            return Some(ty.span);
 +        }
 +    }
 +    None
 +}
 +
 +fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
 +    let last = last_path_segment(qpath);
 +    if_chain! {
 +        if let Some(ref params) = last.args;
 +        if !params.parenthesized;
 +        if let Some(ty) = params.args.iter().find_map(|arg| match arg {
 +            GenericArg::Type(ty) => Some(ty),
 +            _ => None,
 +        });
 +        if let TyKind::Rptr(..) = ty.kind;
 +        then {
 +            return Some(ty.span);
 +        }
 +    }
 +    None
 +}
 +
 +impl Types {
 +    pub fn new(vec_box_size_threshold: u64) -> Self {
 +        Self { vec_box_size_threshold }
 +    }
 +
 +    fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>) {
 +        for input in decl.inputs {
 +            self.check_ty(cx, input, false);
 +        }
 +
 +        if let FnRetTy::Return(ref ty) = decl.output {
 +            self.check_ty(cx, ty, false);
 +        }
 +    }
 +
 +    /// Recursively check for `TypePass` lints in the given type. Stop at the first
 +    /// lint found.
 +    ///
 +    /// The parameter `is_local` distinguishes the context of the type; types from
 +    /// local bindings should only be checked for the `BORROWED_BOX` lint.
 +    #[allow(clippy::too_many_lines)]
 +    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
 +        if hir_ty.span.from_expansion() {
 +            return;
 +        }
 +        match hir_ty.kind {
 +            TyKind::Path(ref qpath) if !is_local => {
 +                let hir_id = hir_ty.hir_id;
 +                let res = qpath_res(cx, qpath, hir_id);
 +                if let Some(def_id) = res.opt_def_id() {
 +                    if Some(def_id) == cx.tcx.lang_items().owned_box() {
 +                        if let Some(span) = match_borrows_parameter(cx, qpath) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                REDUNDANT_ALLOCATION,
 +                                hir_ty.span,
 +                                "usage of `Box<&T>`",
 +                                "try",
 +                                snippet(cx, span, "..").to_string(),
 +                                Applicability::MachineApplicable,
 +                            );
 +                            return; // don't recurse into the type
 +                        }
 +                        if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
 +                            span_lint_and_help(
 +                                cx,
 +                                BOX_VEC,
 +                                hir_ty.span,
 +                                "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
 +                                None,
 +                                "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
 +                            );
 +                            return; // don't recurse into the type
 +                        }
 +                    } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
 +                        if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                REDUNDANT_ALLOCATION,
 +                                hir_ty.span,
 +                                "usage of `Rc<Rc<T>>`",
 +                                "try",
 +                                snippet(cx, span, "..").to_string(),
 +                                Applicability::MachineApplicable,
 +                            );
 +                            return; // don't recurse into the type
 +                        }
-                                 snippet(cx, span, "..").to_string(),
++                        if match_type_parameter(cx, qpath, &paths::BOX).is_some() {
++                            let box_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
++                                GenericArg::Type(ty) => match &ty.kind {
++                                    TyKind::Path(qpath) => qpath,
++                                    _ => return,
++                                },
++                                _ => return,
++                            };
++                            let inner_span = match &last_path_segment(&box_ty).args.unwrap().args[0] {
++                                GenericArg::Type(ty) => ty.span,
++                                _ => return,
++                            };
 +                            span_lint_and_sugg(
 +                                cx,
 +                                REDUNDANT_ALLOCATION,
 +                                hir_ty.span,
 +                                "usage of `Rc<Box<T>>`",
 +                                "try",
++                                format!("Rc<{}>", snippet(cx, inner_span, "..")),
 +                                Applicability::MachineApplicable,
 +                            );
 +                            return; // don't recurse into the type
 +                        }
 +                        if let Some(span) = match_borrows_parameter(cx, qpath) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                REDUNDANT_ALLOCATION,
 +                                hir_ty.span,
 +                                "usage of `Rc<&T>`",
 +                                "try",
 +                                snippet(cx, span, "..").to_string(),
 +                                Applicability::MachineApplicable,
 +                            );
 +                            return; // don't recurse into the type
 +                        }
 +                    } else if cx.tcx.is_diagnostic_item(sym!(vec_type), def_id) {
 +                        if_chain! {
 +                            // Get the _ part of Vec<_>
 +                            if let Some(ref last) = last_path_segment(qpath).args;
 +                            if let Some(ty) = last.args.iter().find_map(|arg| match arg {
 +                                GenericArg::Type(ty) => Some(ty),
 +                                _ => None,
 +                            });
 +                            // ty is now _ at this point
 +                            if let TyKind::Path(ref ty_qpath) = ty.kind;
 +                            let res = qpath_res(cx, ty_qpath, ty.hir_id);
 +                            if let Some(def_id) = res.opt_def_id();
 +                            if Some(def_id) == cx.tcx.lang_items().owned_box();
 +                            // At this point, we know ty is Box<T>, now get T
 +                            if let Some(ref last) = last_path_segment(ty_qpath).args;
 +                            if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
 +                                GenericArg::Type(ty) => Some(ty),
 +                                _ => None,
 +                            });
 +                            let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
 +                            if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
 +                            if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
 +                            if ty_ty_size <= self.vec_box_size_threshold;
 +                            then {
 +                                span_lint_and_sugg(
 +                                    cx,
 +                                    VEC_BOX,
 +                                    hir_ty.span,
 +                                    "`Vec<T>` is already on the heap, the boxing is unnecessary.",
 +                                    "try",
 +                                    format!("Vec<{}>", ty_ty),
 +                                    Applicability::MachineApplicable,
 +                                );
 +                                return; // don't recurse into the type
 +                            }
 +                        }
 +                    } else if cx.tcx.is_diagnostic_item(sym!(option_type), def_id) {
 +                        if match_type_parameter(cx, qpath, &paths::OPTION).is_some() {
 +                            span_lint(
 +                                cx,
 +                                OPTION_OPTION,
 +                                hir_ty.span,
 +                                "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
 +                                 enum if you need to distinguish all 3 cases",
 +                            );
 +                            return; // don't recurse into the type
 +                        }
 +                    } else if match_def_path(cx, def_id, &paths::LINKED_LIST) {
 +                        span_lint_and_help(
 +                            cx,
 +                            LINKEDLIST,
 +                            hir_ty.span,
 +                            "I see you're using a LinkedList! Perhaps you meant some other data structure?",
 +                            None,
 +                            "a `VecDeque` might work",
 +                        );
 +                        return; // don't recurse into the type
 +                    }
 +                }
 +                match *qpath {
 +                    QPath::Resolved(Some(ref ty), ref p) => {
 +                        self.check_ty(cx, ty, is_local);
 +                        for ty in p.segments.iter().flat_map(|seg| {
 +                            seg.args
 +                                .as_ref()
 +                                .map_or_else(|| [].iter(), |params| params.args.iter())
 +                                .filter_map(|arg| match arg {
 +                                    GenericArg::Type(ty) => Some(ty),
 +                                    _ => None,
 +                                })
 +                        }) {
 +                            self.check_ty(cx, ty, is_local);
 +                        }
 +                    },
 +                    QPath::Resolved(None, ref p) => {
 +                        for ty in p.segments.iter().flat_map(|seg| {
 +                            seg.args
 +                                .as_ref()
 +                                .map_or_else(|| [].iter(), |params| params.args.iter())
 +                                .filter_map(|arg| match arg {
 +                                    GenericArg::Type(ty) => Some(ty),
 +                                    _ => None,
 +                                })
 +                        }) {
 +                            self.check_ty(cx, ty, is_local);
 +                        }
 +                    },
 +                    QPath::TypeRelative(ref ty, ref seg) => {
 +                        self.check_ty(cx, ty, is_local);
 +                        if let Some(ref params) = seg.args {
 +                            for ty in params.args.iter().filter_map(|arg| match arg {
 +                                GenericArg::Type(ty) => Some(ty),
 +                                _ => None,
 +                            }) {
 +                                self.check_ty(cx, ty, is_local);
 +                            }
 +                        }
 +                    },
 +                    QPath::LangItem(..) => {},
 +                }
 +            },
 +            TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
 +            // recurse
 +            TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
 +                self.check_ty(cx, ty, is_local)
 +            },
 +            TyKind::Tup(tys) => {
 +                for ty in tys {
 +                    self.check_ty(cx, ty, is_local);
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_ty_rptr(
 +        &mut self,
 +        cx: &LateContext<'_>,
 +        hir_ty: &hir::Ty<'_>,
 +        is_local: bool,
 +        lt: &Lifetime,
 +        mut_ty: &MutTy<'_>,
 +    ) {
 +        match mut_ty.ty.kind {
 +            TyKind::Path(ref qpath) => {
 +                let hir_id = mut_ty.ty.hir_id;
 +                let def = qpath_res(cx, qpath, hir_id);
 +                if_chain! {
 +                    if let Some(def_id) = def.opt_def_id();
 +                    if Some(def_id) == cx.tcx.lang_items().owned_box();
 +                    if let QPath::Resolved(None, ref path) = *qpath;
 +                    if let [ref bx] = *path.segments;
 +                    if let Some(ref params) = bx.args;
 +                    if !params.parenthesized;
 +                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
 +                        GenericArg::Type(ty) => Some(ty),
 +                        _ => None,
 +                    });
 +                    then {
 +                        if is_any_trait(inner) {
 +                            // Ignore `Box<Any>` types; see issue #1884 for details.
 +                            return;
 +                        }
 +
 +                        let ltopt = if lt.is_elided() {
 +                            String::new()
 +                        } else {
 +                            format!("{} ", lt.name.ident().as_str())
 +                        };
 +
 +                        if mut_ty.mutbl == Mutability::Mut {
 +                            // Ignore `&mut Box<T>` types; see issue #2907 for
 +                            // details.
 +                            return;
 +                        }
 +                        let mut applicability = Applicability::MachineApplicable;
 +                        span_lint_and_sugg(
 +                            cx,
 +                            BORROWED_BOX,
 +                            hir_ty.span,
 +                            "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
 +                            "try",
 +                            format!(
 +                                "&{}{}",
 +                                ltopt,
 +                                &snippet_with_applicability(cx, inner.span, "..", &mut applicability)
 +                            ),
 +                            Applicability::Unspecified,
 +                        );
 +                        return; // don't recurse into the type
 +                    }
 +                };
 +                self.check_ty(cx, &mut_ty.ty, is_local);
 +            },
 +            _ => self.check_ty(cx, &mut_ty.ty, is_local),
 +        }
 +    }
 +}
 +
 +// Returns true if given type is `Any` trait.
 +fn is_any_trait(t: &hir::Ty<'_>) -> bool {
 +    if_chain! {
 +        if let TyKind::TraitObject(ref traits, _) = t.kind;
 +        if !traits.is_empty();
 +        // Only Send/Sync can be used as additional traits, so it is enough to
 +        // check only the first trait.
 +        if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
 +        then {
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for binding a unit value.
 +    ///
 +    /// **Why is this bad?** A unit value cannot usefully be used anywhere. So
 +    /// binding one is kind of pointless.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = {
 +    ///     1;
 +    /// };
 +    /// ```
 +    pub LET_UNIT_VALUE,
 +    pedantic,
 +    "creating a `let` binding to a value of unit type, which usually can't be used afterwards"
 +}
 +
 +declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LetUnitValue {
 +    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
 +        if let StmtKind::Local(ref local) = stmt.kind {
 +            if is_unit(cx.typeck_results().pat_ty(&local.pat)) {
 +                if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
 +                    return;
 +                }
 +                if higher::is_from_for_desugar(local) {
 +                    return;
 +                }
 +                span_lint_and_then(
 +                    cx,
 +                    LET_UNIT_VALUE,
 +                    stmt.span,
 +                    "this let-binding has unit value",
 +                    |diag| {
 +                        if let Some(expr) = &local.init {
 +                            let snip = snippet_with_macro_callsite(cx, expr.span, "()");
 +                            diag.span_suggestion(
 +                                stmt.span,
 +                                "omit the `let` binding",
 +                                format!("{};", snip),
 +                                Applicability::MachineApplicable, // snippet
 +                            );
 +                        }
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for comparisons to unit. This includes all binary
 +    /// comparisons (like `==` and `<`) and asserts.
 +    ///
 +    /// **Why is this bad?** Unit is always equal to itself, and thus is just a
 +    /// clumsily written constant. Mostly this happens when someone accidentally
 +    /// adds semicolons at the end of the operands.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # fn foo() {};
 +    /// # fn bar() {};
 +    /// # fn baz() {};
 +    /// if {
 +    ///     foo();
 +    /// } == {
 +    ///     bar();
 +    /// } {
 +    ///     baz();
 +    /// }
 +    /// ```
 +    /// is equal to
 +    /// ```rust
 +    /// # fn foo() {};
 +    /// # fn bar() {};
 +    /// # fn baz() {};
 +    /// {
 +    ///     foo();
 +    ///     bar();
 +    ///     baz();
 +    /// }
 +    /// ```
 +    ///
 +    /// For asserts:
 +    /// ```rust
 +    /// # fn foo() {};
 +    /// # fn bar() {};
 +    /// assert_eq!({ foo(); }, { bar(); });
 +    /// ```
 +    /// will always succeed
 +    pub UNIT_CMP,
 +    correctness,
 +    "comparing unit values"
 +}
 +
 +declare_lint_pass!(UnitCmp => [UNIT_CMP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UnitCmp {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 +        if expr.span.from_expansion() {
 +            if let Some(callee) = expr.span.source_callee() {
 +                if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
 +                    if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
 +                        let op = cmp.node;
 +                        if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
 +                            let result = match &*symbol.as_str() {
 +                                "assert_eq" | "debug_assert_eq" => "succeed",
 +                                "assert_ne" | "debug_assert_ne" => "fail",
 +                                _ => return,
 +                            };
 +                            span_lint(
 +                                cx,
 +                                UNIT_CMP,
 +                                expr.span,
 +                                &format!(
 +                                    "`{}` of unit values detected. This will always {}",
 +                                    symbol.as_str(),
 +                                    result
 +                                ),
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +            return;
 +        }
 +        if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
 +            let op = cmp.node;
 +            if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
 +                let result = match op {
 +                    BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
 +                    _ => "false",
 +                };
 +                span_lint(
 +                    cx,
 +                    UNIT_CMP,
 +                    expr.span,
 +                    &format!(
 +                        "{}-comparison of unit values detected. This will always be {}",
 +                        op.as_str(),
 +                        result
 +                    ),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for passing a unit value as an argument to a function without using a
 +    /// unit literal (`()`).
 +    ///
 +    /// **Why is this bad?** This is likely the result of an accidental semicolon.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// foo({
 +    ///     let a = bar();
 +    ///     baz(a);
 +    /// })
 +    /// ```
 +    pub UNIT_ARG,
 +    complexity,
 +    "passing unit to a function"
 +}
 +
 +declare_lint_pass!(UnitArg => [UNIT_ARG]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UnitArg {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        // apparently stuff in the desugaring of `?` can trigger this
 +        // so check for that here
 +        // only the calls to `Try::from_error` is marked as desugared,
 +        // so we need to check both the current Expr and its parent.
 +        if is_questionmark_desugar_marked_call(expr) {
 +            return;
 +        }
 +        if_chain! {
 +            let map = &cx.tcx.hir();
 +            let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
 +            if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
 +            if is_questionmark_desugar_marked_call(parent_expr);
 +            then {
 +                return;
 +            }
 +        }
 +
 +        match expr.kind {
 +            ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => {
 +                let args_to_recover = args
 +                    .iter()
 +                    .filter(|arg| {
 +                        if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) {
 +                            !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar))
 +                        } else {
 +                            false
 +                        }
 +                    })
 +                    .collect::<Vec<_>>();
 +                if !args_to_recover.is_empty() {
 +                    lint_unit_args(cx, expr, &args_to_recover);
 +                }
 +            },
 +            _ => (),
 +        }
 +    }
 +}
 +
 +fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
 +    let mut applicability = Applicability::MachineApplicable;
 +    let (singular, plural) = if args_to_recover.len() > 1 {
 +        ("", "s")
 +    } else {
 +        ("a ", "")
 +    };
 +    span_lint_and_then(
 +        cx,
 +        UNIT_ARG,
 +        expr.span,
 +        &format!("passing {}unit value{} to a function", singular, plural),
 +        |db| {
 +            let mut or = "";
 +            args_to_recover
 +                .iter()
 +                .filter_map(|arg| {
 +                    if_chain! {
 +                        if let ExprKind::Block(block, _) = arg.kind;
 +                        if block.expr.is_none();
 +                        if let Some(last_stmt) = block.stmts.iter().last();
 +                        if let StmtKind::Semi(last_expr) = last_stmt.kind;
 +                        if let Some(snip) = snippet_opt(cx, last_expr.span);
 +                        then {
 +                            Some((
 +                                last_stmt.span,
 +                                snip,
 +                            ))
 +                        }
 +                        else {
 +                            None
 +                        }
 +                    }
 +                })
 +                .for_each(|(span, sugg)| {
 +                    db.span_suggestion(
 +                        span,
 +                        "remove the semicolon from the last statement in the block",
 +                        sugg,
 +                        Applicability::MaybeIncorrect,
 +                    );
 +                    or = "or ";
 +                });
 +            let sugg = args_to_recover
 +                .iter()
 +                .filter(|arg| !is_empty_block(arg))
 +                .enumerate()
 +                .map(|(i, arg)| {
 +                    let indent = if i == 0 {
 +                        0
 +                    } else {
 +                        indent_of(cx, expr.span).unwrap_or(0)
 +                    };
 +                    format!(
 +                        "{}{};",
 +                        " ".repeat(indent),
 +                        snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability)
 +                    )
 +                })
 +                .collect::<Vec<String>>();
 +            let mut and = "";
 +            if !sugg.is_empty() {
 +                let plural = if sugg.len() > 1 { "s" } else { "" };
 +                db.span_suggestion(
 +                    expr.span.with_hi(expr.span.lo()),
 +                    &format!("{}move the expression{} in front of the call...", or, plural),
 +                    format!("{}\n", sugg.join("\n")),
 +                    applicability,
 +                );
 +                and = "...and "
 +            }
 +            db.multipart_suggestion(
 +                &format!("{}use {}unit literal{} instead", and, singular, plural),
 +                args_to_recover
 +                    .iter()
 +                    .map(|arg| (arg.span, "()".to_string()))
 +                    .collect::<Vec<_>>(),
 +                applicability,
 +            );
 +        },
 +    );
 +}
 +
 +fn is_empty_block(expr: &Expr<'_>) -> bool {
 +    matches!(
 +        expr.kind,
 +        ExprKind::Block(
 +            Block {
 +                stmts: &[], expr: None, ..
 +            },
 +            _,
 +        )
 +    )
 +}
 +
 +fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
 +    use rustc_span::hygiene::DesugaringKind;
 +    if let ExprKind::Call(ref callee, _) = expr.kind {
 +        callee.span.is_desugaring(DesugaringKind::QuestionMark)
 +    } else {
 +        false
 +    }
 +}
 +
 +fn is_unit(ty: Ty<'_>) -> bool {
 +    matches!(ty.kind, ty::Tuple(slice) if slice.is_empty())
 +}
 +
 +fn is_unit_literal(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts from any numerical to a float type where
 +    /// the receiving type cannot store all values from the original type without
 +    /// rounding errors. This possible rounding is to be expected, so this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// Basically, this warns on casting any integer with 32 or more bits to `f32`
 +    /// or any 64-bit integer to `f64`.
 +    ///
 +    /// **Why is this bad?** It's not bad at all. But in some applications it can be
 +    /// helpful to know where precision loss can take place. This lint can help find
 +    /// those places in the code.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = u64::MAX;
 +    /// x as f64;
 +    /// ```
 +    pub CAST_PRECISION_LOSS,
 +    pedantic,
 +    "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts from a signed to an unsigned numerical
 +    /// type. In this case, negative values wrap around to large positive values,
 +    /// which can be quite surprising in practice. However, as the cast works as
 +    /// defined, this lint is `Allow` by default.
 +    ///
 +    /// **Why is this bad?** Possibly surprising results. You can activate this lint
 +    /// as a one-time check to see where numerical wrapping can arise.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let y: i8 = -1;
 +    /// y as u128; // will return 18446744073709551615
 +    /// ```
 +    pub CAST_SIGN_LOSS,
 +    pedantic,
 +    "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts between numerical types that may
 +    /// truncate large values. This is expected behavior, so the cast is `Allow` by
 +    /// default.
 +    ///
 +    /// **Why is this bad?** In some problem domains, it is good practice to avoid
 +    /// truncation. This lint can be activated to help assess where additional
 +    /// checks could be beneficial.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// fn as_u8(x: u64) -> u8 {
 +    ///     x as u8
 +    /// }
 +    /// ```
 +    pub CAST_POSSIBLE_TRUNCATION,
 +    pedantic,
 +    "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts from an unsigned type to a signed type of
 +    /// the same size. Performing such a cast is a 'no-op' for the compiler,
 +    /// i.e., nothing is changed at the bit level, and the binary representation of
 +    /// the value is reinterpreted. This can cause wrapping if the value is too big
 +    /// for the target signed type. However, the cast works as defined, so this lint
 +    /// is `Allow` by default.
 +    ///
 +    /// **Why is this bad?** While such a cast is not bad in itself, the results can
 +    /// be surprising when this is not the intended behavior, as demonstrated by the
 +    /// example below.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// u32::MAX as i32; // will yield a value of `-1`
 +    /// ```
 +    pub CAST_POSSIBLE_WRAP,
 +    pedantic,
 +    "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts between numerical types that may
 +    /// be replaced by safe conversion functions.
 +    ///
 +    /// **Why is this bad?** Rust's `as` keyword will perform many kinds of
 +    /// conversions, including silently lossy conversions. Conversion functions such
 +    /// as `i32::from` will only perform lossless conversions. Using the conversion
 +    /// functions prevents conversions from turning into silent lossy conversions if
 +    /// the types of the input expressions ever change, and make it easier for
 +    /// people reading the code to know that the conversion is lossless.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     x as u64
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `::from` would look like this:
 +    ///
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     u64::from(x)
 +    /// }
 +    /// ```
 +    pub CAST_LOSSLESS,
 +    pedantic,
 +    "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts to the same type.
 +    ///
 +    /// **Why is this bad?** It's just unnecessary.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let _ = 2i32 as i32;
 +    /// ```
 +    pub UNNECESSARY_CAST,
 +    complexity,
 +    "cast to the same type, e.g., `x as i32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts from a less-strictly-aligned pointer to a
 +    /// more-strictly-aligned pointer
 +    ///
 +    /// **Why is this bad?** Dereferencing the resulting pointer may be undefined
 +    /// behavior.
 +    ///
 +    /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
 +    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
 +    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let _ = (&1u8 as *const u8) as *const u16;
 +    /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
 +    /// ```
 +    pub CAST_PTR_ALIGNMENT,
 +    pedantic,
 +    "cast from a pointer to a more-strictly-aligned pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts of function pointers to something other than usize
 +    ///
 +    /// **Why is this bad?**
 +    /// Casting a function pointer to anything other than usize/isize is not portable across
 +    /// architectures, because you end up losing bits if the target type is too small or end up with a
 +    /// bunch of extra bits that waste space and add more instructions to the final binary than
 +    /// strictly necessary for the problem
 +    ///
 +    /// Casting to isize also doesn't make sense since there are no signed addresses.
 +    ///
 +    /// **Example**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// fn fun() -> i32 { 1 }
 +    /// let a = fun as i64;
 +    ///
 +    /// // Good
 +    /// fn fun2() -> i32 { 1 }
 +    /// let a = fun2 as usize;
 +    /// ```
 +    pub FN_TO_NUMERIC_CAST,
 +    style,
 +    "casting a function pointer to a numeric type other than usize"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
 +    /// store address.
 +    ///
 +    /// **Why is this bad?**
 +    /// Such a cast discards some bits of the function's address. If this is intended, it would be more
 +    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
 +    /// a comment) to perform the truncation.
 +    ///
 +    /// **Example**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// fn fn1() -> i16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as i32;
 +    ///
 +    /// // Better: Cast to usize first, then comment with the reason for the truncation
 +    /// fn fn2() -> i16 {
 +    ///     1
 +    /// };
 +    /// let fn_ptr = fn2 as usize;
 +    /// let fn_ptr_truncated = fn_ptr as i32;
 +    /// ```
 +    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    style,
 +    "casting a function pointer to a numeric type not wide enough to store the address"
 +}
 +
 +/// Returns the size in bits of an integral type.
 +/// Will return 0 if the type is not an int or uint variant
 +fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
 +    match typ.kind {
 +        ty::Int(i) => match i {
 +            IntTy::Isize => tcx.data_layout.pointer_size.bits(),
 +            IntTy::I8 => 8,
 +            IntTy::I16 => 16,
 +            IntTy::I32 => 32,
 +            IntTy::I64 => 64,
 +            IntTy::I128 => 128,
 +        },
 +        ty::Uint(i) => match i {
 +            UintTy::Usize => tcx.data_layout.pointer_size.bits(),
 +            UintTy::U8 => 8,
 +            UintTy::U16 => 16,
 +            UintTy::U32 => 32,
 +            UintTy::U64 => 64,
 +            UintTy::U128 => 128,
 +        },
 +        _ => 0,
 +    }
 +}
 +
 +fn is_isize_or_usize(typ: Ty<'_>) -> bool {
 +    matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 +}
 +
 +fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
 +    let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
 +    let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
 +    let arch_dependent_str = "on targets with 64-bit wide pointers ";
 +    let from_nbits_str = if arch_dependent {
 +        "64".to_owned()
 +    } else if is_isize_or_usize(cast_from) {
 +        "32 or 64".to_owned()
 +    } else {
 +        int_ty_to_nbits(cast_from, cx.tcx).to_string()
 +    };
 +    span_lint(
 +        cx,
 +        CAST_PRECISION_LOSS,
 +        expr.span,
 +        &format!(
 +            "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
 +             but `{1}`'s mantissa is only {4} bits wide)",
 +            cast_from,
 +            if cast_to_f64 { "f64" } else { "f32" },
 +            if arch_dependent { arch_dependent_str } else { "" },
 +            from_nbits_str,
 +            mantissa_nbits
 +        ),
 +    );
 +}
 +
 +fn should_strip_parens(op: &Expr<'_>, snip: &str) -> bool {
 +    if let ExprKind::Binary(_, _, _) = op.kind {
 +        if snip.starts_with('(') && snip.ends_with(')') {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
 +    if in_constant(cx, expr.hir_id) {
 +        return;
 +    }
 +    // The suggestion is to use a function call, so if the original expression
 +    // has parens on the outside, they are no longer needed.
 +    let mut applicability = Applicability::MachineApplicable;
 +    let opt = snippet_opt(cx, op.span);
 +    let sugg = opt.as_ref().map_or_else(
 +        || {
 +            applicability = Applicability::HasPlaceholders;
 +            ".."
 +        },
 +        |snip| {
 +            if should_strip_parens(op, snip) {
 +                &snip[1..snip.len() - 1]
 +            } else {
 +                snip.as_str()
 +            }
 +        },
 +    );
 +
 +    span_lint_and_sugg(
 +        cx,
 +        CAST_LOSSLESS,
 +        expr.span,
 +        &format!(
 +            "casting `{}` to `{}` may become silently lossy if you later change the type",
 +            cast_from, cast_to
 +        ),
 +        "try",
 +        format!("{}::from({})", cast_to, sugg),
 +        applicability,
 +    );
 +}
 +
 +enum ArchSuffix {
 +    _32,
 +    _64,
 +    None,
 +}
 +
 +fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    if !cast_from.is_signed() || cast_to.is_signed() {
 +        return;
 +    }
 +
 +    // don't lint for positive constants
 +    let const_val = constant(cx, &cx.typeck_results(), op);
 +    if_chain! {
 +        if let Some((const_val, _)) = const_val;
 +        if let Constant::Int(n) = const_val;
 +        if let ty::Int(ity) = cast_from.kind;
 +        if sext(cx.tcx, n, ity) >= 0;
 +        then {
 +            return
 +        }
 +    }
 +
 +    // don't lint for the result of methods that always return non-negative values
 +    if let ExprKind::MethodCall(ref path, _, _, _) = op.kind {
 +        let mut method_name = path.ident.name.as_str();
 +        let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
 +
 +        if_chain! {
 +            if method_name == "unwrap";
 +            if let Some(arglist) = method_chain_args(op, &["unwrap"]);
 +            if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind;
 +            then {
 +                method_name = inner_path.ident.name.as_str();
 +            }
 +        }
 +
 +        if allowed_methods.iter().any(|&name| method_name == name) {
 +            return;
 +        }
 +    }
 +
 +    span_lint(
 +        cx,
 +        CAST_SIGN_LOSS,
 +        expr.span,
 +        &format!(
 +            "casting `{}` to `{}` may lose the sign of the value",
 +            cast_from, cast_to
 +        ),
 +    );
 +}
 +
 +fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    let arch_64_suffix = " on targets with 64-bit wide pointers";
 +    let arch_32_suffix = " on targets with 32-bit wide pointers";
 +    let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
 +    let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
 +    let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
 +    let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) =
 +        match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
 +            (true, true) | (false, false) => (
 +                to_nbits < from_nbits,
 +                ArchSuffix::None,
 +                to_nbits == from_nbits && cast_unsigned_to_signed,
 +                ArchSuffix::None,
 +            ),
 +            (true, false) => (
 +                to_nbits <= 32,
 +                if to_nbits == 32 {
 +                    ArchSuffix::_64
 +                } else {
 +                    ArchSuffix::None
 +                },
 +                to_nbits <= 32 && cast_unsigned_to_signed,
 +                ArchSuffix::_32,
 +            ),
 +            (false, true) => (
 +                from_nbits == 64,
 +                ArchSuffix::_32,
 +                cast_unsigned_to_signed,
 +                if from_nbits == 64 {
 +                    ArchSuffix::_64
 +                } else {
 +                    ArchSuffix::_32
 +                },
 +            ),
 +        };
 +    if span_truncation {
 +        span_lint(
 +            cx,
 +            CAST_POSSIBLE_TRUNCATION,
 +            expr.span,
 +            &format!(
 +                "casting `{}` to `{}` may truncate the value{}",
 +                cast_from,
 +                cast_to,
 +                match suffix_truncation {
 +                    ArchSuffix::_32 => arch_32_suffix,
 +                    ArchSuffix::_64 => arch_64_suffix,
 +                    ArchSuffix::None => "",
 +                }
 +            ),
 +        );
 +    }
 +    if span_wrap {
 +        span_lint(
 +            cx,
 +            CAST_POSSIBLE_WRAP,
 +            expr.span,
 +            &format!(
 +                "casting `{}` to `{}` may wrap around the value{}",
 +                cast_from,
 +                cast_to,
 +                match suffix_wrap {
 +                    ArchSuffix::_32 => arch_32_suffix,
 +                    ArchSuffix::_64 => arch_64_suffix,
 +                    ArchSuffix::None => "",
 +                }
 +            ),
 +        );
 +    }
 +}
 +
 +fn check_lossless(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
 +    let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
 +    let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
 +    if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned
 +    {
 +        span_lossless_lint(cx, expr, op, cast_from, cast_to);
 +    }
 +}
 +
 +declare_lint_pass!(Casts => [
 +    CAST_PRECISION_LOSS,
 +    CAST_SIGN_LOSS,
 +    CAST_POSSIBLE_TRUNCATION,
 +    CAST_POSSIBLE_WRAP,
 +    CAST_LOSSLESS,
 +    UNNECESSARY_CAST,
 +    CAST_PTR_ALIGNMENT,
 +    FN_TO_NUMERIC_CAST,
 +    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +]);
 +
 +// Check if the given type is either `core::ffi::c_void` or
 +// one of the platform specific `libc::<platform>::c_void` of libc.
 +fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 +    if let ty::Adt(adt, _) = ty.kind {
 +        let names = cx.get_def_path(adt.did);
 +
 +        if names.is_empty() {
 +            return false;
 +        }
 +        if names[0] == sym!(libc) || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +/// 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,
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Casts {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::Cast(ref ex, _) = expr.kind {
 +            let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
 +            lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
 +            if let ExprKind::Lit(ref lit) = ex.kind {
 +                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 {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            UNNECESSARY_CAST,
 +                            expr.span,
 +                            &format!("casting integer literal to `{}` is unnecessary", cast_to),
 +                            "try",
 +                            format!("{}_{}", n, cast_to),
 +                            Applicability::MachineApplicable,
 +                        );
 +                        return;
 +                    }
 +                }
 +                match lit.node {
 +                    LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
 +                    _ => {
 +                        if cast_from.kind == cast_to.kind && !in_external_macro(cx.sess(), expr.span) {
 +                            span_lint(
 +                                cx,
 +                                UNNECESSARY_CAST,
 +                                expr.span,
 +                                &format!(
 +                                    "casting to the same type is unnecessary (`{}` -> `{}`)",
 +                                    cast_from, cast_to
 +                                ),
 +                            );
 +                        }
 +                    },
 +                }
 +            }
 +            if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
 +                lint_numeric_casts(cx, expr, ex, cast_from, cast_to);
 +            }
 +
 +            lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
 +        }
 +    }
 +}
 +
 +fn lint_numeric_casts<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &Expr<'tcx>,
 +    cast_expr: &Expr<'_>,
 +    cast_from: Ty<'tcx>,
 +    cast_to: Ty<'tcx>,
 +) {
 +    match (cast_from.is_integral(), cast_to.is_integral()) {
 +        (true, false) => {
 +            let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
 +            let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind {
 +                32
 +            } else {
 +                64
 +            };
 +            if is_isize_or_usize(cast_from) || from_nbits >= to_nbits {
 +                span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64);
 +            }
 +            if from_nbits < to_nbits {
 +                span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
 +            }
 +        },
 +        (false, true) => {
 +            span_lint(
 +                cx,
 +                CAST_POSSIBLE_TRUNCATION,
 +                expr.span,
 +                &format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to),
 +            );
 +            if !cast_to.is_signed() {
 +                span_lint(
 +                    cx,
 +                    CAST_SIGN_LOSS,
 +                    expr.span,
 +                    &format!(
 +                        "casting `{}` to `{}` may lose the sign of the value",
 +                        cast_from, cast_to
 +                    ),
 +                );
 +            }
 +        },
 +        (true, true) => {
 +            check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to);
 +            check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
 +            check_lossless(cx, expr, cast_expr, cast_from, cast_to);
 +        },
 +        (false, false) => {
 +            if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind, &cast_to.kind) {
 +                span_lint(
 +                    cx,
 +                    CAST_POSSIBLE_TRUNCATION,
 +                    expr.span,
 +                    "casting `f64` to `f32` may truncate the value",
 +                );
 +            }
 +            if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind, &cast_to.kind) {
 +                span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
 +            }
 +        },
 +    }
 +}
 +
 +fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
 +    if_chain! {
 +        if let ty::RawPtr(from_ptr_ty) = &cast_from.kind;
 +        if let ty::RawPtr(to_ptr_ty) = &cast_to.kind;
 +        if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty);
 +        if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty);
 +        if from_layout.align.abi < to_layout.align.abi;
 +        // with c_void, we inherently need to trust the user
 +        if !is_c_void(cx, from_ptr_ty.ty);
 +        // when casting from a ZST, we don't know enough to properly lint
 +        if !from_layout.is_zst();
 +        then {
 +            span_lint(
 +                cx,
 +                CAST_PTR_ALIGNMENT,
 +                expr.span,
 +                &format!(
 +                    "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
 +                    cast_from,
 +                    cast_to,
 +                    from_layout.align.abi.bytes(),
 +                    to_layout.align.abi.bytes(),
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +fn lint_fn_to_numeric_cast(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    cast_expr: &Expr<'_>,
 +    cast_from: Ty<'_>,
 +    cast_to: Ty<'_>,
 +) {
 +    // We only want to check casts to `ty::Uint` or `ty::Int`
 +    match cast_to.kind {
 +        ty::Uint(_) | ty::Int(..) => { /* continue on */ },
 +        _ => return,
 +    }
 +    match cast_from.kind {
 +        ty::FnDef(..) | ty::FnPtr(_) => {
 +            let mut applicability = Applicability::MaybeIncorrect;
 +            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
 +
 +            let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
 +            if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
 +                span_lint_and_sugg(
 +                    cx,
 +                    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +                    expr.span,
 +                    &format!(
 +                        "casting function pointer `{}` to `{}`, which truncates the value",
 +                        from_snippet, cast_to
 +                    ),
 +                    "try",
 +                    format!("{} as usize", from_snippet),
 +                    applicability,
 +                );
 +            } else if cast_to.kind != ty::Uint(UintTy::Usize) {
 +                span_lint_and_sugg(
 +                    cx,
 +                    FN_TO_NUMERIC_CAST,
 +                    expr.span,
 +                    &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
 +                    "try",
 +                    format!("{} as usize", from_snippet),
 +                    applicability,
 +                );
 +            }
 +        },
 +        _ => {},
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for types used in structs, parameters and `let`
 +    /// declarations above a certain complexity threshold.
 +    ///
 +    /// **Why is this bad?** Too complex types make the code less readable. Consider
 +    /// using a `type` definition to simplify them.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::rc::Rc;
 +    /// struct Foo {
 +    ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
 +    /// }
 +    /// ```
 +    pub TYPE_COMPLEXITY,
 +    complexity,
 +    "usage of very complex types that might be better factored into `type` definitions"
 +}
 +
 +pub struct TypeComplexity {
 +    threshold: u64,
 +}
 +
 +impl TypeComplexity {
 +    #[must_use]
 +    pub fn new(threshold: u64) -> Self {
 +        Self { threshold }
 +    }
 +}
 +
 +impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        _: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        _: &'tcx Body<'_>,
 +        _: Span,
 +        _: HirId,
 +    ) {
 +        self.check_fndecl(cx, decl);
 +    }
 +
 +    fn check_struct_field(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::StructField<'_>) {
 +        // enum variants are also struct fields now
 +        self.check_type(cx, &field.ty);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        match item.kind {
 +            ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => self.check_type(cx, ty),
 +            // functions, enums, structs, impls and traits are covered
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        match item.kind {
 +            TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
 +            TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl),
 +            // methods with default impl are covered by check_fn
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        match item.kind {
 +            ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty),
 +            // methods are covered by check_fn
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
 +        if let Some(ref ty) = local.ty {
 +            self.check_type(cx, ty);
 +        }
 +    }
 +}
 +
 +impl<'tcx> TypeComplexity {
 +    fn check_fndecl(&self, cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>) {
 +        for arg in decl.inputs {
 +            self.check_type(cx, arg);
 +        }
 +        if let FnRetTy::Return(ref ty) = decl.output {
 +            self.check_type(cx, ty);
 +        }
 +    }
 +
 +    fn check_type(&self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
 +        if ty.span.from_expansion() {
 +            return;
 +        }
 +        let score = {
 +            let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
 +            visitor.visit_ty(ty);
 +            visitor.score
 +        };
 +
 +        if score > self.threshold {
 +            span_lint(
 +                cx,
 +                TYPE_COMPLEXITY,
 +                ty.span,
 +                "very complex type used. Consider factoring parts into `type` definitions",
 +            );
 +        }
 +    }
 +}
 +
 +/// Walks a type and assigns a complexity score to it.
 +struct TypeComplexityVisitor {
 +    /// total complexity score of the type
 +    score: u64,
 +    /// current nesting level
 +    nest: u64,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
 +        let (add_score, sub_nest) = match ty.kind {
 +            // _, &x and *x have only small overhead; don't mess with nesting level
 +            TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
 +
 +            // the "normal" components of a type: named types, arrays/tuples
 +            TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
 +
 +            // function types bring a lot of overhead
 +            TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
 +
 +            TyKind::TraitObject(ref param_bounds, _) => {
 +                let has_lifetime_parameters = param_bounds.iter().any(|bound| {
 +                    bound
 +                        .bound_generic_params
 +                        .iter()
 +                        .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
 +                });
 +                if has_lifetime_parameters {
 +                    // complex trait bounds like A<'a, 'b>
 +                    (50 * self.nest, 1)
 +                } else {
 +                    // simple trait bounds like A + B
 +                    (20 * self.nest, 0)
 +                }
 +            },
 +
 +            _ => (0, 0),
 +        };
 +        self.score += add_score;
 +        self.nest += sub_nest;
 +        walk_ty(self, ty);
 +        self.nest -= sub_nest;
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for expressions where a character literal is cast
 +    /// to `u8` and suggests using a byte literal instead.
 +    ///
 +    /// **Why is this bad?** In general, casting values to smaller types is
 +    /// error-prone and should be avoided where possible. In the particular case of
 +    /// converting a character literal to u8, it is easy to avoid by just using a
 +    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
 +    /// than `'a' as u8`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// 'x' as u8
 +    /// ```
 +    ///
 +    /// A better version, using the byte literal:
 +    ///
 +    /// ```rust,ignore
 +    /// b'x'
 +    /// ```
 +    pub CHAR_LIT_AS_U8,
 +    complexity,
 +    "casting a character literal to `u8` truncates"
 +}
 +
 +declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CharLitAsU8 {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if !expr.span.from_expansion();
 +            if let ExprKind::Cast(e, _) = &expr.kind;
 +            if let ExprKind::Lit(l) = &e.kind;
 +            if let LitKind::Char(c) = l.node;
 +            if ty::Uint(UintTy::U8) == cx.typeck_results().expr_ty(expr).kind;
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
 +
 +                span_lint_and_then(
 +                    cx,
 +                    CHAR_LIT_AS_U8,
 +                    expr.span,
 +                    "casting a character literal to `u8` truncates",
 +                    |diag| {
 +                        diag.note("`char` is four bytes wide, but `u8` is a single byte");
 +
 +                        if c.is_ascii() {
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "use a byte literal instead",
 +                                format!("b{}", snippet),
 +                                applicability,
 +                            );
 +                        }
 +                });
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for comparisons where one side of the relation is
 +    /// either the minimum or maximum value for its type and warns if it involves a
 +    /// case that is always true or always false. Only integer and boolean types are
 +    /// checked.
 +    ///
 +    /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
 +    /// that it is possible for `x` to be less than the minimum. Expressions like
 +    /// `max < x` are probably mistakes.
 +    ///
 +    /// **Known problems:** For `usize` the size of the current compile target will
 +    /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
 +    /// a comparison to detect target pointer width will trigger this lint. One can
 +    /// use `mem::sizeof` and compare its value or conditional compilation
 +    /// attributes
 +    /// like `#[cfg(target_pointer_width = "64")] ..` instead.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// let vec: Vec<isize> = Vec::new();
 +    /// if vec.len() <= 0 {}
 +    /// if 100 > i32::MAX {}
 +    /// ```
 +    pub ABSURD_EXTREME_COMPARISONS,
 +    correctness,
 +    "a comparison with a maximum or minimum value that is always true or false"
 +}
 +
 +declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
 +
 +enum ExtremeType {
 +    Minimum,
 +    Maximum,
 +}
 +
 +struct ExtremeExpr<'a> {
 +    which: ExtremeType,
 +    expr: &'a Expr<'a>,
 +}
 +
 +enum AbsurdComparisonResult {
 +    AlwaysFalse,
 +    AlwaysTrue,
 +    InequalityImpossible,
 +}
 +
 +fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
 +    if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
 +        let precast_ty = cx.typeck_results().expr_ty(cast_exp);
 +        let cast_ty = cx.typeck_results().expr_ty(expr);
 +
 +        return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
 +    }
 +
 +    false
 +}
 +
 +fn detect_absurd_comparison<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    op: BinOpKind,
 +    lhs: &'tcx Expr<'_>,
 +    rhs: &'tcx Expr<'_>,
 +) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
 +    use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
 +    use crate::types::ExtremeType::{Maximum, Minimum};
 +    use crate::utils::comparisons::{normalize_comparison, Rel};
 +
 +    // absurd comparison only makes sense on primitive types
 +    // primitive types don't implement comparison operators with each other
 +    if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
 +        return None;
 +    }
 +
 +    // comparisons between fix sized types and target sized types are considered unanalyzable
 +    if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
 +        return None;
 +    }
 +
 +    let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
 +
 +    let lx = detect_extreme_expr(cx, normalized_lhs);
 +    let rx = detect_extreme_expr(cx, normalized_rhs);
 +
 +    Some(match rel {
 +        Rel::Lt => {
 +            match (lx, rx) {
 +                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
 +                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
 +                _ => return None,
 +            }
 +        },
 +        Rel::Le => {
 +            match (lx, rx) {
 +                (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
 +                (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
 +                (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
 +                (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
 +                _ => return None,
 +            }
 +        },
 +        Rel::Ne | Rel::Eq => return None,
 +    })
 +}
 +
 +fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
 +    use crate::types::ExtremeType::{Maximum, Minimum};
 +
 +    let ty = cx.typeck_results().expr_ty(expr);
 +
 +    let cv = constant(cx, cx.typeck_results(), expr)?.0;
 +
 +    let which = match (&ty.kind, cv) {
 +        (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
 +        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
 +            Minimum
 +        },
 +
 +        (&ty::Bool, Constant::Bool(true)) => Maximum,
 +        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
 +            Maximum
 +        },
 +        (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
 +
 +        _ => return None,
 +    };
 +    Some(ExtremeExpr { which, expr })
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
 +        use crate::types::ExtremeType::{Maximum, Minimum};
 +
 +        if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
 +            if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
 +                if !expr.span.from_expansion() {
 +                    let msg = "this comparison involving the minimum or maximum element for this \
 +                               type contains a case that is always true or always false";
 +
 +                    let conclusion = match result {
 +                        AlwaysFalse => "this comparison is always false".to_owned(),
 +                        AlwaysTrue => "this comparison is always true".to_owned(),
 +                        InequalityImpossible => format!(
 +                            "the case where the two sides are not equal never occurs, consider using `{} == {}` \
 +                             instead",
 +                            snippet(cx, lhs.span, "lhs"),
 +                            snippet(cx, rhs.span, "rhs")
 +                        ),
 +                    };
 +
 +                    let help = format!(
 +                        "because `{}` is the {} value for this type, {}",
 +                        snippet(cx, culprit.expr.span, "x"),
 +                        match culprit.which {
 +                            Minimum => "minimum",
 +                            Maximum => "maximum",
 +                        },
 +                        conclusion
 +                    );
 +
 +                    span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for comparisons where the relation is always either
 +    /// true or false, but where one side has been upcast so that the comparison is
 +    /// necessary. Only integer types are checked.
 +    ///
 +    /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
 +    /// will mistakenly imply that it is possible for `x` to be outside the range of
 +    /// `u8`.
 +    ///
 +    /// **Known problems:**
 +    /// https://github.com/rust-lang/rust-clippy/issues/886
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x: u8 = 1;
 +    /// (x as u32) > 300;
 +    /// ```
 +    pub INVALID_UPCAST_COMPARISONS,
 +    pedantic,
 +    "a comparison involving an upcast which is always true or false"
 +}
 +
 +declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
 +
 +#[derive(Copy, Clone, Debug, Eq)]
 +enum FullInt {
 +    S(i128),
 +    U(u128),
 +}
 +
 +impl FullInt {
 +    #[allow(clippy::cast_sign_loss)]
 +    #[must_use]
 +    fn cmp_s_u(s: i128, u: u128) -> Ordering {
 +        if s < 0 {
 +            Ordering::Less
 +        } else if u > (i128::MAX as u128) {
 +            Ordering::Greater
 +        } else {
 +            (s as u128).cmp(&u)
 +        }
 +    }
 +}
 +
 +impl PartialEq for FullInt {
 +    #[must_use]
 +    fn eq(&self, other: &Self) -> bool {
 +        self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
 +    }
 +}
 +
 +impl PartialOrd for FullInt {
 +    #[must_use]
 +    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 +        Some(match (self, other) {
 +            (&Self::S(s), &Self::S(o)) => s.cmp(&o),
 +            (&Self::U(s), &Self::U(o)) => s.cmp(&o),
 +            (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
 +            (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
 +        })
 +    }
 +}
 +impl Ord for FullInt {
 +    #[must_use]
 +    fn cmp(&self, other: &Self) -> Ordering {
 +        self.partial_cmp(other)
 +            .expect("`partial_cmp` for FullInt can never return `None`")
 +    }
 +}
 +
 +fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
 +    if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
 +        let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
 +        let cast_ty = cx.typeck_results().expr_ty(expr);
 +        // if it's a cast from i32 to u32 wrapping will invalidate all these checks
 +        if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
 +            return None;
 +        }
 +        match pre_cast_ty.kind {
 +            ty::Int(int_ty) => Some(match int_ty {
 +                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
 +                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
 +                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
 +                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
 +                IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
 +                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
 +            }),
 +            ty::Uint(uint_ty) => Some(match uint_ty {
 +                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
 +                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
 +                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
 +                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
 +                UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
 +                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
 +            }),
 +            _ => None,
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
 +    let val = constant(cx, cx.typeck_results(), expr)?.0;
 +    if let Constant::Int(const_int) = val {
 +        match cx.typeck_results().expr_ty(expr).kind {
 +            ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
 +            ty::Uint(_) => Some(FullInt::U(const_int)),
 +            _ => None,
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
 +    if let ExprKind::Cast(ref cast_val, _) = expr.kind {
 +        span_lint(
 +            cx,
 +            INVALID_UPCAST_COMPARISONS,
 +            span,
 +            &format!(
 +                "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
 +                snippet(cx, cast_val.span, "the expression"),
 +                if always { "true" } else { "false" },
 +            ),
 +        );
 +    }
 +}
 +
 +fn upcast_comparison_bounds_err<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    rel: comparisons::Rel,
 +    lhs_bounds: Option<(FullInt, FullInt)>,
 +    lhs: &'tcx Expr<'_>,
 +    rhs: &'tcx Expr<'_>,
 +    invert: bool,
 +) {
 +    use crate::utils::comparisons::Rel;
 +
 +    if let Some((lb, ub)) = lhs_bounds {
 +        if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
 +            if rel == Rel::Eq || rel == Rel::Ne {
 +                if norm_rhs_val < lb || norm_rhs_val > ub {
 +                    err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
 +                }
 +            } else if match rel {
 +                Rel::Lt => {
 +                    if invert {
 +                        norm_rhs_val < lb
 +                    } else {
 +                        ub < norm_rhs_val
 +                    }
 +                },
 +                Rel::Le => {
 +                    if invert {
 +                        norm_rhs_val <= lb
 +                    } else {
 +                        ub <= norm_rhs_val
 +                    }
 +                },
 +                Rel::Eq | Rel::Ne => unreachable!(),
 +            } {
 +                err_upcast_comparison(cx, span, lhs, true)
 +            } else if match rel {
 +                Rel::Lt => {
 +                    if invert {
 +                        norm_rhs_val >= ub
 +                    } else {
 +                        lb >= norm_rhs_val
 +                    }
 +                },
 +                Rel::Le => {
 +                    if invert {
 +                        norm_rhs_val > ub
 +                    } else {
 +                        lb > norm_rhs_val
 +                    }
 +                },
 +                Rel::Eq | Rel::Ne => unreachable!(),
 +            } {
 +                err_upcast_comparison(cx, span, lhs, false)
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
 +            let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
 +            let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
 +                val
 +            } else {
 +                return;
 +            };
 +
 +            let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
 +            let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
 +
 +            upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
 +            upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for public `impl` or `fn` missing generalization
 +    /// over different hashers and implicitly defaulting to the default hashing
 +    /// algorithm (`SipHash`).
 +    ///
 +    /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
 +    /// used with them.
 +    ///
 +    /// **Known problems:** Suggestions for replacing constructors can contain
 +    /// false-positives. Also applying suggestions can require modification of other
 +    /// pieces of code, possibly including external crates.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::collections::HashMap;
 +    /// # use std::hash::{Hash, BuildHasher};
 +    /// # trait Serialize {};
 +    /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
 +    ///
 +    /// pub fn foo(map: &mut HashMap<i32, i32>) { }
 +    /// ```
 +    /// could be rewritten as
 +    /// ```rust
 +    /// # use std::collections::HashMap;
 +    /// # use std::hash::{Hash, BuildHasher};
 +    /// # trait Serialize {};
 +    /// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
 +    ///
 +    /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
 +    /// ```
 +    pub IMPLICIT_HASHER,
 +    pedantic,
 +    "missing generalization over different hashers"
 +}
 +
 +declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
 +    #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        use rustc_span::BytePos;
 +
 +        fn suggestion<'tcx>(
 +            cx: &LateContext<'tcx>,
 +            diag: &mut DiagnosticBuilder<'_>,
 +            generics_span: Span,
 +            generics_suggestion_span: Span,
 +            target: &ImplicitHasherType<'_>,
 +            vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
 +        ) {
 +            let generics_snip = snippet(cx, generics_span, "");
 +            // trim `<` `>`
 +            let generics_snip = if generics_snip.is_empty() {
 +                ""
 +            } else {
 +                &generics_snip[1..generics_snip.len() - 1]
 +            };
 +
 +            multispan_sugg(
 +                diag,
 +                "consider adding a type parameter",
 +                vec![
 +                    (
 +                        generics_suggestion_span,
 +                        format!(
 +                            "<{}{}S: ::std::hash::BuildHasher{}>",
 +                            generics_snip,
 +                            if generics_snip.is_empty() { "" } else { ", " },
 +                            if vis.suggestions.is_empty() {
 +                                ""
 +                            } else {
 +                                // request users to add `Default` bound so that generic constructors can be used
 +                                " + Default"
 +                            },
 +                        ),
 +                    ),
 +                    (
 +                        target.span(),
 +                        format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
 +                    ),
 +                ],
 +            );
 +
 +            if !vis.suggestions.is_empty() {
 +                multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
 +            }
 +        }
 +
 +        if !cx.access_levels.is_exported(item.hir_id) {
 +            return;
 +        }
 +
 +        match item.kind {
 +            ItemKind::Impl {
 +                ref generics,
 +                self_ty: ref ty,
 +                ref items,
 +                ..
 +            } => {
 +                let mut vis = ImplicitHasherTypeVisitor::new(cx);
 +                vis.visit_ty(ty);
 +
 +                for target in &vis.found {
 +                    if differing_macro_contexts(item.span, target.span()) {
 +                        return;
 +                    }
 +
 +                    let generics_suggestion_span = generics.span.substitute_dummy({
 +                        let pos = snippet_opt(cx, item.span.until(target.span()))
 +                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
 +                        if let Some(pos) = pos {
 +                            Span::new(pos, pos, item.span.data().ctxt)
 +                        } else {
 +                            return;
 +                        }
 +                    });
 +
 +                    let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
 +                    for item in items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
 +                        ctr_vis.visit_impl_item(item);
 +                    }
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        IMPLICIT_HASHER,
 +                        target.span(),
 +                        &format!(
 +                            "impl for `{}` should be generalized over different hashers",
 +                            target.type_name()
 +                        ),
 +                        move |diag| {
 +                            suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
 +                        },
 +                    );
 +                }
 +            },
 +            ItemKind::Fn(ref sig, ref generics, body_id) => {
 +                let body = cx.tcx.hir().body(body_id);
 +
 +                for ty in sig.decl.inputs {
 +                    let mut vis = ImplicitHasherTypeVisitor::new(cx);
 +                    vis.visit_ty(ty);
 +
 +                    for target in &vis.found {
 +                        if in_external_macro(cx.sess(), generics.span) {
 +                            continue;
 +                        }
 +                        let generics_suggestion_span = generics.span.substitute_dummy({
 +                            let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
 +                                .and_then(|snip| {
 +                                    let i = snip.find("fn")?;
 +                                    Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
 +                                })
 +                                .expect("failed to create span for type parameters");
 +                            Span::new(pos, pos, item.span.data().ctxt)
 +                        });
 +
 +                        let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
 +                        ctr_vis.visit_body(body);
 +
 +                        span_lint_and_then(
 +                            cx,
 +                            IMPLICIT_HASHER,
 +                            target.span(),
 +                            &format!(
 +                                "parameter of type `{}` should be generalized over different hashers",
 +                                target.type_name()
 +                            ),
 +                            move |diag| {
 +                                suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
 +                            },
 +                        );
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +enum ImplicitHasherType<'tcx> {
 +    HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
 +    HashSet(Span, Ty<'tcx>, Cow<'static, str>),
 +}
 +
 +impl<'tcx> ImplicitHasherType<'tcx> {
 +    /// Checks that `ty` is a target type without a `BuildHasher`.
 +    fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
 +        if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind {
 +            let params: Vec<_> = path
 +                .segments
 +                .last()
 +                .as_ref()?
 +                .args
 +                .as_ref()?
 +                .args
 +                .iter()
 +                .filter_map(|arg| match arg {
 +                    GenericArg::Type(ty) => Some(ty),
 +                    _ => None,
 +                })
 +                .collect();
 +            let params_len = params.len();
 +
 +            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 +
 +            if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) && params_len == 2 {
 +                Some(ImplicitHasherType::HashMap(
 +                    hir_ty.span,
 +                    ty,
 +                    snippet(cx, params[0].span, "K"),
 +                    snippet(cx, params[1].span, "V"),
 +                ))
 +            } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) && params_len == 1 {
 +                Some(ImplicitHasherType::HashSet(
 +                    hir_ty.span,
 +                    ty,
 +                    snippet(cx, params[0].span, "T"),
 +                ))
 +            } else {
 +                None
 +            }
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn type_name(&self) -> &'static str {
 +        match *self {
 +            ImplicitHasherType::HashMap(..) => "HashMap",
 +            ImplicitHasherType::HashSet(..) => "HashSet",
 +        }
 +    }
 +
 +    fn type_arguments(&self) -> String {
 +        match *self {
 +            ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
 +            ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
 +        }
 +    }
 +
 +    fn ty(&self) -> Ty<'tcx> {
 +        match *self {
 +            ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
 +        }
 +    }
 +
 +    fn span(&self) -> Span {
 +        match *self {
 +            ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
 +        }
 +    }
 +}
 +
 +struct ImplicitHasherTypeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    found: Vec<ImplicitHasherType<'tcx>>,
 +}
 +
 +impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
 +    fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self { cx, found: vec![] }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
 +        if let Some(target) = ImplicitHasherType::new(self.cx, t) {
 +            self.found.push(target);
 +        }
 +
 +        walk_ty(self, t);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Looks for default-hasher-dependent constructors like `HashMap::new`.
 +struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
 +    target: &'b ImplicitHasherType<'tcx>,
 +    suggestions: BTreeMap<Span, String>,
 +}
 +
 +impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
 +    fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            maybe_typeck_results: cx.maybe_typeck_results(),
 +            target,
 +            suggestions: BTreeMap::new(),
 +        }
 +    }
 +}
 +
 +impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_body(&mut self, body: &'tcx Body<'_>) {
 +        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
 +        walk_body(self, body);
 +        self.maybe_typeck_results = old_maybe_typeck_results;
 +    }
 +
 +    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(ref fun, ref args) = e.kind;
 +            if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
 +            if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
 +            then {
 +                if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
 +                    return;
 +                }
 +
 +                if match_path(ty_path, &paths::HASHMAP) {
 +                    if method.ident.name == sym!(new) {
 +                        self.suggestions
 +                            .insert(e.span, "HashMap::default()".to_string());
 +                    } else if method.ident.name == sym!(with_capacity) {
 +                        self.suggestions.insert(
 +                            e.span,
 +                            format!(
 +                                "HashMap::with_capacity_and_hasher({}, Default::default())",
 +                                snippet(self.cx, args[0].span, "capacity"),
 +                            ),
 +                        );
 +                    }
 +                } else if match_path(ty_path, &paths::HASHSET) {
 +                    if method.ident.name == sym!(new) {
 +                        self.suggestions
 +                            .insert(e.span, "HashSet::default()".to_string());
 +                    } else if method.ident.name == sym!(with_capacity) {
 +                        self.suggestions.insert(
 +                            e.span,
 +                            format!(
 +                                "HashSet::with_capacity_and_hasher({}, Default::default())",
 +                                snippet(self.cx, args[0].span, "capacity"),
 +                            ),
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +
 +        walk_expr(self, e);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
 +    ///
 +    /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
 +    /// `UnsafeCell` is the only way to obtain aliasable data that is considered
 +    /// mutable.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// fn x(r: &i32) {
 +    ///     unsafe {
 +    ///         *(r as *const _ as *mut _) += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Instead consider using interior mutability types.
 +    ///
 +    /// ```rust
 +    /// use std::cell::UnsafeCell;
 +    ///
 +    /// fn x(r: &UnsafeCell<i32>) {
 +    ///     unsafe {
 +    ///         *r.get() += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    pub CAST_REF_TO_MUT,
 +    correctness,
 +    "a cast of reference to a mutable pointer"
 +}
 +
 +declare_lint_pass!(RefToMut => [CAST_REF_TO_MUT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for RefToMut {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.kind;
 +            if let ExprKind::Cast(e, t) = &e.kind;
 +            if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
 +            if let ExprKind::Cast(e, t) = &e.kind;
 +            if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
 +            if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind;
 +            then {
 +                span_lint(
 +                    cx,
 +                    CAST_REF_TO_MUT,
 +                    expr.span,
 +                    "casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`",
 +                );
 +            }
 +        }
 +    }
 +}
index 9fe771cef45bfbb80f691517f847512dda07bb08,0000000000000000000000000000000000000000..7f4f16f8faf96225c201528e2d1f9a3804490da8
mode 100644,000000..100644
--- /dev/null
@@@ -1,408 -1,0 +1,408 @@@
- use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 +#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 +
 +use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
 +use crate::utils::{over, span_lint_and_then};
-         tokens: None
 +use rustc_ast::mut_visit::*;
 +use rustc_ast::ptr::P;
++use rustc_ast::{self as ast, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
 +use rustc_ast_pretty::pprust;
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::DUMMY_SP;
 +
 +use std::cell::Cell;
 +use std::mem;
 +
 +declare_clippy_lint! {
 +    /// **What it does:**
 +    ///
 +    /// Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and
 +    /// suggests replacing the pattern with a nested one, `Some(0 | 2)`.
 +    ///
 +    /// Another way to think of this is that it rewrites patterns in
 +    /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
 +    ///
 +    /// **Why is this bad?**
 +    ///
 +    /// In the example above, `Some` is repeated, which unncessarily complicates the pattern.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// fn main() {
 +    ///     if let Some(0) | Some(2) = Some(0) {}
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// #![feature(or_patterns)]
 +    ///
 +    /// fn main() {
 +    ///     if let Some(0 | 2) = Some(0) {}
 +    /// }
 +    /// ```
 +    pub UNNESTED_OR_PATTERNS,
 +    pedantic,
 +    "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
 +}
 +
 +declare_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
 +
 +impl EarlyLintPass for UnnestedOrPatterns {
 +    fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
 +        lint_unnested_or_patterns(cx, &a.pat);
 +    }
 +
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
 +        if let ast::ExprKind::Let(pat, _) = &e.kind {
 +            lint_unnested_or_patterns(cx, pat);
 +        }
 +    }
 +
 +    fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
 +        lint_unnested_or_patterns(cx, &p.pat);
 +    }
 +
 +    fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
 +        lint_unnested_or_patterns(cx, &l.pat);
 +    }
 +}
 +
 +fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
 +    if !cx.sess.features_untracked().or_patterns {
 +        // Do not suggest nesting the patterns if the feature `or_patterns` is not enabled.
 +        return;
 +    }
 +
 +    if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
 +        // This is a leaf pattern, so cloning is unprofitable.
 +        return;
 +    }
 +
 +    let mut pat = P(pat.clone());
 +
 +    // Nix all the paren patterns everywhere so that they aren't in our way.
 +    remove_all_parens(&mut pat);
 +
 +    // Transform all unnested or-patterns into nested ones, and if there were none, quit.
 +    if !unnest_or_patterns(&mut pat) {
 +        return;
 +    }
 +
 +    span_lint_and_then(cx, UNNESTED_OR_PATTERNS, pat.span, "unnested or-patterns", |db| {
 +        insert_necessary_parens(&mut pat);
 +        db.span_suggestion_verbose(
 +            pat.span,
 +            "nest the patterns",
 +            pprust::pat_to_string(&pat),
 +            Applicability::MachineApplicable,
 +        );
 +    });
 +}
 +
 +/// Remove all `(p)` patterns in `pat`.
 +fn remove_all_parens(pat: &mut P<Pat>) {
 +    struct Visitor;
 +    impl MutVisitor for Visitor {
 +        fn visit_pat(&mut self, pat: &mut P<Pat>) {
 +            noop_visit_pat(pat, self);
 +            let inner = match &mut pat.kind {
 +                Paren(i) => mem::replace(&mut i.kind, Wild),
 +                _ => return,
 +            };
 +            pat.kind = inner;
 +        }
 +    }
 +    Visitor.visit_pat(pat);
 +}
 +
 +/// Insert parens where necessary according to Rust's precedence rules for patterns.
 +fn insert_necessary_parens(pat: &mut P<Pat>) {
 +    struct Visitor;
 +    impl MutVisitor for Visitor {
 +        fn visit_pat(&mut self, pat: &mut P<Pat>) {
 +            use ast::{BindingMode::*, Mutability::*};
 +            noop_visit_pat(pat, self);
 +            let target = match &mut pat.kind {
 +                // `i @ a | b`, `box a | b`, and `& mut? a | b`.
 +                Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
 +                Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
 +                _ => return,
 +            };
 +            target.kind = Paren(P(take_pat(target)));
 +        }
 +    }
 +    Visitor.visit_pat(pat);
 +}
 +
 +/// Unnest or-patterns `p0 | ... | p1` in the pattern `pat`.
 +/// For example, this would transform `Some(0) | FOO | Some(2)` into `Some(0 | 2) | FOO`.
 +fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
 +    struct Visitor {
 +        changed: bool,
 +    }
 +    impl MutVisitor for Visitor {
 +        fn visit_pat(&mut self, p: &mut P<Pat>) {
 +            // This is a bottom up transformation, so recurse first.
 +            noop_visit_pat(p, self);
 +
 +            // Don't have an or-pattern? Just quit early on.
 +            let alternatives = match &mut p.kind {
 +                Or(ps) => ps,
 +                _ => return,
 +            };
 +
 +            // Collapse or-patterns directly nested in or-patterns.
 +            let mut idx = 0;
 +            let mut this_level_changed = false;
 +            while idx < alternatives.len() {
 +                let inner = if let Or(ps) = &mut alternatives[idx].kind {
 +                    mem::take(ps)
 +                } else {
 +                    idx += 1;
 +                    continue;
 +                };
 +                this_level_changed = true;
 +                alternatives.splice(idx..=idx, inner);
 +            }
 +
 +            // Focus on `p_n` and then try to transform all `p_i` where `i > n`.
 +            let mut focus_idx = 0;
 +            while focus_idx < alternatives.len() {
 +                this_level_changed |= transform_with_focus_on_idx(alternatives, focus_idx);
 +                focus_idx += 1;
 +            }
 +            self.changed |= this_level_changed;
 +
 +            // Deal with `Some(Some(0)) | Some(Some(1))`.
 +            if this_level_changed {
 +                noop_visit_pat(p, self);
 +            }
 +        }
 +    }
 +
 +    let mut visitor = Visitor { changed: false };
 +    visitor.visit_pat(pat);
 +    visitor.changed
 +}
 +
 +/// Match `$scrutinee` against `$pat` and extract `$then` from it.
 +/// Panics if there is no match.
 +macro_rules! always_pat {
 +    ($scrutinee:expr, $pat:pat => $then:expr) => {
 +        match $scrutinee {
 +            $pat => $then,
 +            _ => unreachable!(),
 +        }
 +    };
 +}
 +
 +/// Focus on `focus_idx` in `alternatives`,
 +/// attempting to extend it with elements of the same constructor `C`
 +/// in `alternatives[focus_idx + 1..]`.
 +fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) -> bool {
 +    // Extract the kind; we'll need to make some changes in it.
 +    let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild);
 +    // We'll focus on `alternatives[focus_idx]`,
 +    // so we're draining from `alternatives[focus_idx + 1..]`.
 +    let start = focus_idx + 1;
 +
 +    // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
 +    let changed = match &mut focus_kind {
 +        // These pattern forms are "leafs" and do not have sub-patterns.
 +        // Therefore they are not some form of constructor `C`,
 +        // with which a pattern `C(p_0)` may be formed,
 +        // which we would want to join with other `C(p_j)`s.
 +        Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
 +        // Dealt with elsewhere.
 +        | Or(_) | Paren(_) => false,
 +        // Transform `box x | ... | box y` into `box (x | y)`.
 +        //
 +        // The cases below until `Slice(...)` deal with *singleton* products.
 +        // These patterns have the shape `C(p)`, and not e.g., `C(p0, ..., pn)`.
 +        Box(target) => extend_with_matching(
 +            target, start, alternatives,
 +            |k| matches!(k, Box(_)),
 +            |k| always_pat!(k, Box(p) => p),
 +        ),
 +        // Transform `&m x | ... | &m y` into `&m (x | y)`.
 +        Ref(target, m1) => extend_with_matching(
 +            target, start, alternatives,
 +            |k| matches!(k, Ref(_, m2) if m1 == m2), // Mutabilities must match.
 +            |k| always_pat!(k, Ref(p, _) => p),
 +        ),
 +        // Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`.
 +        Ident(b1, i1, Some(target)) => extend_with_matching(
 +            target, start, alternatives,
 +            // Binding names must match.
 +            |k| matches!(k, Ident(b2, i2, Some(_)) if b1 == b2 && eq_id(*i1, *i2)),
 +            |k| always_pat!(k, Ident(_, _, Some(p)) => p),
 +        ),
 +        // Transform `[pre, x, post] | ... | [pre, y, post]` into `[pre, x | y, post]`.
 +        Slice(ps1) => extend_with_matching_product(
 +            ps1, start, alternatives,
 +            |k, ps1, idx| matches!(k, Slice(ps2) if eq_pre_post(ps1, ps2, idx)),
 +            |k| always_pat!(k, Slice(ps) => ps),
 +        ),
 +        // Transform `(pre, x, post) | ... | (pre, y, post)` into `(pre, x | y, post)`.
 +        Tuple(ps1) => extend_with_matching_product(
 +            ps1, start, alternatives,
 +            |k, ps1, idx| matches!(k, Tuple(ps2) if eq_pre_post(ps1, ps2, idx)),
 +            |k| always_pat!(k, Tuple(ps) => ps),
 +        ),
 +        // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
 +        TupleStruct(path1, ps1) => extend_with_matching_product(
 +            ps1, start, alternatives,
 +            |k, ps1, idx| matches!(
 +                k,
 +                TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
 +            ),
 +            |k| always_pat!(k, TupleStruct(_, ps) => ps),
 +        ),
 +        // Transform a record pattern `S { fp_0, ..., fp_n }`.
 +        Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives),
 +    };
 +
 +    alternatives[focus_idx].kind = focus_kind;
 +    changed
 +}
 +
 +/// Here we focusing on a record pattern `S { fp_0, ..., fp_n }`.
 +/// In particular, for a record pattern, the order in which the field patterns is irrelevant.
 +/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
 +/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
 +fn extend_with_struct_pat(
 +    path1: &ast::Path,
 +    fps1: &mut Vec<ast::FieldPat>,
 +    rest1: bool,
 +    start: usize,
 +    alternatives: &mut Vec<P<Pat>>,
 +) -> bool {
 +    (0..fps1.len()).any(|idx| {
 +        let pos_in_2 = Cell::new(None); // The element `k`.
 +        let tail_or = drain_matching(
 +            start,
 +            alternatives,
 +            |k| {
 +                matches!(k, Struct(path2, fps2, rest2)
 +                if rest1 == *rest2 // If one struct pattern has `..` so must the other.
 +                && eq_path(path1, path2)
 +                && fps1.len() == fps2.len()
 +                && fps1.iter().enumerate().all(|(idx_1, fp1)| {
 +                    if idx_1 == idx {
 +                        // In the case of `k`, we merely require identical field names
 +                        // so that we will transform into `ident_k: p1_k | p2_k`.
 +                        let pos = fps2.iter().position(|fp2| eq_id(fp1.ident, fp2.ident));
 +                        pos_in_2.set(pos);
 +                        pos.is_some()
 +                    } else {
 +                        fps2.iter().any(|fp2| eq_field_pat(fp1, fp2))
 +                    }
 +                }))
 +            },
 +            // Extract `p2_k`.
 +            |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
 +        );
 +        extend_with_tail_or(&mut fps1[idx].pat, tail_or)
 +    })
 +}
 +
 +/// Like `extend_with_matching` but for products with > 1 factor, e.g., `C(p_0, ..., p_n)`.
 +/// Here, the idea is that we fixate on some `p_k` in `C`,
 +/// allowing it to vary between two `targets` and `ps2` (returned by `extract`),
 +/// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post),
 +/// where `~` denotes semantic equality.
 +fn extend_with_matching_product(
 +    targets: &mut Vec<P<Pat>>,
 +    start: usize,
 +    alternatives: &mut Vec<P<Pat>>,
 +    predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
 +    extract: impl Fn(PatKind) -> Vec<P<Pat>>,
 +) -> bool {
 +    (0..targets.len()).any(|idx| {
 +        let tail_or = drain_matching(
 +            start,
 +            alternatives,
 +            |k| predicate(k, targets, idx),
 +            |k| extract(k).swap_remove(idx),
 +        );
 +        extend_with_tail_or(&mut targets[idx], tail_or)
 +    })
 +}
 +
 +/// Extract the pattern from the given one and replace it with `Wild`.
 +/// This is meant for temporarily swapping out the pattern for manipulation.
 +fn take_pat(from: &mut Pat) -> Pat {
 +    let dummy = Pat {
 +        id: DUMMY_NODE_ID,
 +        kind: Wild,
 +        span: DUMMY_SP,
++        tokens: None,
 +    };
 +    mem::replace(from, dummy)
 +}
 +
 +/// Extend `target` as an or-pattern with the alternatives
 +/// in `tail_or` if there are any and return if there were.
 +fn extend_with_tail_or(target: &mut Pat, tail_or: Vec<P<Pat>>) -> bool {
 +    fn extend(target: &mut Pat, mut tail_or: Vec<P<Pat>>) {
 +        match target {
 +            // On an existing or-pattern in the target, append to it.
 +            Pat { kind: Or(ps), .. } => ps.append(&mut tail_or),
 +            // Otherwise convert the target to an or-pattern.
 +            target => {
 +                let mut init_or = vec![P(take_pat(target))];
 +                init_or.append(&mut tail_or);
 +                target.kind = Or(init_or);
 +            },
 +        }
 +    }
 +
 +    let changed = !tail_or.is_empty();
 +    if changed {
 +        // Extend the target.
 +        extend(target, tail_or);
 +    }
 +    changed
 +}
 +
 +// Extract all inner patterns in `alternatives` matching our `predicate`.
 +// Only elements beginning with `start` are considered for extraction.
 +fn drain_matching(
 +    start: usize,
 +    alternatives: &mut Vec<P<Pat>>,
 +    predicate: impl Fn(&PatKind) -> bool,
 +    extract: impl Fn(PatKind) -> P<Pat>,
 +) -> Vec<P<Pat>> {
 +    let mut tail_or = vec![];
 +    let mut idx = 0;
 +    for pat in alternatives.drain_filter(|p| {
 +        // Check if we should extract, but only if `idx >= start`.
 +        idx += 1;
 +        idx > start && predicate(&p.kind)
 +    }) {
 +        tail_or.push(extract(pat.into_inner().kind));
 +    }
 +    tail_or
 +}
 +
 +fn extend_with_matching(
 +    target: &mut Pat,
 +    start: usize,
 +    alternatives: &mut Vec<P<Pat>>,
 +    predicate: impl Fn(&PatKind) -> bool,
 +    extract: impl Fn(PatKind) -> P<Pat>,
 +) -> bool {
 +    extend_with_tail_or(target, drain_matching(start, alternatives, predicate, extract))
 +}
 +
 +/// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`?
 +fn eq_pre_post(ps1: &[P<Pat>], ps2: &[P<Pat>], idx: usize) -> bool {
 +    ps1.len() == ps2.len()
 +        && ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
 +        && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r))
 +        && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r))
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7548c6afa973afec4838369bb06ed8b6bd5efd3c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,144 @@@
++use if_chain::if_chain;
++use rustc_ast::ast;
++use rustc_ast::visit::FnKind;
++use rustc_errors::Applicability;
++use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::source_map::Span;
++use rustc_span::BytePos;
++
++use crate::utils::span_lint_and_sugg;
++
++declare_clippy_lint! {
++    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
++    ///
++    /// **Why is this bad?** Such expressions add no value, but can make the code
++    /// less readable. Depending on formatting they can make a `break` or `return`
++    /// statement look like a function call.
++    ///
++    /// **Known problems:** None.
++    ///
++    /// **Example:**
++    /// ```rust
++    /// fn return_unit() -> () {
++    ///     ()
++    /// }
++    /// ```
++    pub UNUSED_UNIT,
++    style,
++    "needless unit expression"
++}
++
++declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
++
++impl EarlyLintPass for UnusedUnit {
++    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
++        if_chain! {
++            if let ast::FnRetTy::Ty(ref ty) = kind.decl().output;
++            if let ast::TyKind::Tup(ref vals) = ty.kind;
++            if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
++            then {
++                lint_unneeded_unit_return(cx, ty, span);
++            }
++        }
++    }
++
++    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
++        if_chain! {
++            if let Some(ref stmt) = block.stmts.last();
++            if let ast::StmtKind::Expr(ref expr) = stmt.kind;
++            if is_unit_expr(expr) && !stmt.span.from_expansion();
++            then {
++                let sp = expr.span;
++                span_lint_and_sugg(
++                    cx,
++                    UNUSED_UNIT,
++                    sp,
++                    "unneeded unit expression",
++                    "remove the final `()`",
++                    String::new(),
++                    Applicability::MachineApplicable,
++                );
++            }
++        }
++    }
++
++    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
++        match e.kind {
++            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
++                if is_unit_expr(expr) && !expr.span.from_expansion() {
++                    span_lint_and_sugg(
++                        cx,
++                        UNUSED_UNIT,
++                        expr.span,
++                        "unneeded `()`",
++                        "remove the `()`",
++                        String::new(),
++                        Applicability::MachineApplicable,
++                    );
++                }
++            },
++            _ => (),
++        }
++    }
++
++    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
++        let segments = &poly.trait_ref.path.segments;
++
++        if_chain! {
++            if segments.len() == 1;
++            if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str());
++            if let Some(args) = &segments[0].args;
++            if let ast::GenericArgs::Parenthesized(generic_args) = &**args;
++            if let ast::FnRetTy::Ty(ty) = &generic_args.output;
++            if ty.kind.is_unit();
++            then {
++                lint_unneeded_unit_return(cx, ty, generic_args.span);
++            }
++        }
++    }
++}
++
++// get the def site
++#[must_use]
++fn get_def(span: Span) -> Option<Span> {
++    if span.from_expansion() {
++        Some(span.ctxt().outer_expn_data().def_site)
++    } else {
++        None
++    }
++}
++
++// is this expr a `()` unit?
++fn is_unit_expr(expr: &ast::Expr) -> bool {
++    if let ast::ExprKind::Tup(ref vals) = expr.kind {
++        vals.is_empty()
++    } else {
++        false
++    }
++}
++
++fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
++    let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
++        fn_source
++            .rfind("->")
++            .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
++                (
++                    #[allow(clippy::cast_possible_truncation)]
++                    ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
++                    Applicability::MachineApplicable,
++                )
++            })
++    } else {
++        (ty.span, Applicability::MaybeIncorrect)
++    };
++    span_lint_and_sugg(
++        cx,
++        UNUSED_UNIT,
++        ret_span,
++        "unneeded unit return type",
++        "remove the `-> ()`",
++        String::new(),
++        appl,
++    );
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c7e62ecd3d2c0c1e7fe6e8c149ad8ebbed8d4ae
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,140 @@@
++use crate::utils::{is_type_diagnostic_item, method_chain_args, return_ty, span_lint_and_then, walk_ptrs_ty};
++use if_chain::if_chain;
++use rustc_hir as hir;
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::hir::map::Map;
++use rustc_middle::ty;
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::Span;
++
++declare_clippy_lint! {
++    /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()`
++    ///
++    /// **Why is this bad?** These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
++    ///
++    /// **Known problems:** This can cause false positives in functions that handle both recoverable and non recoverable errors.
++    ///
++    /// **Example:**
++    /// Before:
++    /// ```rust
++    /// fn divisible_by_3(i_str: String) -> Result<(), String> {
++    ///     let i = i_str
++    ///         .parse::<i32>()
++    ///         .expect("cannot divide the input by three");
++    ///
++    ///     if i % 3 != 0 {
++    ///         Err("Number is not divisible by 3")?
++    ///     }
++    ///
++    ///     Ok(())
++    /// }
++    /// ```
++    ///
++    /// After:
++    /// ```rust
++    /// fn divisible_by_3(i_str: String) -> Result<(), String> {
++    ///     let i = i_str
++    ///         .parse::<i32>()
++    ///         .map_err(|e| format!("cannot divide the input by three: {}", e))?;
++    ///
++    ///     if i % 3 != 0 {
++    ///         Err("Number is not divisible by 3")?
++    ///     }
++    ///
++    ///     Ok(())
++    /// }
++    /// ```
++    pub UNWRAP_IN_RESULT,
++    restriction,
++    "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`"
++}
++
++declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
++
++impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
++    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
++        if_chain! {
++            // first check if it's a method or function
++            if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
++            // checking if its return type is `result` or `option`
++            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type))
++                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type));
++            then {
++                lint_impl_body(cx, impl_item.span, impl_item);
++            }
++        }
++    }
++}
++
++use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
++use rustc_hir::{Expr, ImplItemKind};
++
++struct FindExpectUnwrap<'a, 'tcx> {
++    lcx: &'a LateContext<'tcx>,
++    typeck_results: &'tcx ty::TypeckResults<'tcx>,
++    result: Vec<Span>,
++}
++
++impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
++    type Map = Map<'tcx>;
++
++    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
++        // check for `expect`
++        if let Some(arglists) = method_chain_args(expr, &["expect"]) {
++            let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
++            if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
++                || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
++            {
++                self.result.push(expr.span);
++            }
++        }
++
++        // check for `unwrap`
++        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
++            let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
++            if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
++                || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
++            {
++                self.result.push(expr.span);
++            }
++        }
++
++        // and check sub-expressions
++        intravisit::walk_expr(self, expr);
++    }
++
++    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
++        NestedVisitorMap::None
++    }
++}
++
++fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
++    if_chain! {
++
++        if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
++        then {
++            let body = cx.tcx.hir().body(body_id);
++            let impl_item_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
++            let mut fpu = FindExpectUnwrap {
++                lcx: cx,
++                typeck_results: cx.tcx.typeck(impl_item_def_id),
++                result: Vec::new(),
++            };
++            fpu.visit_expr(&body.value);
++
++            // if we've found one, lint
++            if  !fpu.result.is_empty()  {
++                span_lint_and_then(
++                    cx,
++                    UNWRAP_IN_RESULT,
++                    impl_span,
++                    "used unwrap or expect in a function that returns result or option",
++                    move |diag| {
++                        diag.help(
++                            "unwrap and expect should not be used in a function that returns result or option" );
++                        diag.span_note(fpu.result, "potential non-recoverable error(s)");
++                    });
++            }
++        }
++    }
++}
index 776c6bc57ca6f857c4d86b699d99a4d5f2351f41,0000000000000000000000000000000000000000..427a1b6577315c271611a0cd9c5c5d8e721a4346
mode 100644,000000..100644
--- /dev/null
@@@ -1,269 -1,0 +1,269 @@@
-     "Unnecessary structure name repetition whereas `Self` is applicable"
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath,
 +    TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_middle::ty::{DefIdTree, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::kw;
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use crate::utils::{differing_macro_contexts, span_lint_and_sugg};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for unnecessary repetition of structure name when a
 +    /// replacement with `Self` is applicable.
 +    ///
 +    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
 +    /// name
 +    /// feels inconsistent.
 +    ///
 +    /// **Known problems:**
 +    /// - False positive when using associated types (#2843)
 +    /// - False positives in some situations when using generics (#3410)
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// struct Foo {}
 +    /// impl Foo {
 +    ///     fn new() -> Foo {
 +    ///         Foo {}
 +    ///     }
 +    /// }
 +    /// ```
 +    /// could be
 +    /// ```rust
 +    /// struct Foo {}
 +    /// impl Foo {
 +    ///     fn new() -> Self {
 +    ///         Self {}
 +    ///     }
 +    /// }
 +    /// ```
 +    pub USE_SELF,
 +    nursery,
++    "unnecessary structure name repetition whereas `Self` is applicable"
 +}
 +
 +declare_lint_pass!(UseSelf => [USE_SELF]);
 +
 +const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 +
 +fn span_use_self_lint(cx: &LateContext<'_>, path: &Path<'_>, last_segment: Option<&PathSegment<'_>>) {
 +    let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG));
 +
 +    // Path segments only include actual path, no methods or fields.
 +    let last_path_span = last_segment.ident.span;
 +
 +    if differing_macro_contexts(path.span, last_path_span) {
 +        return;
 +    }
 +
 +    // Only take path up to the end of last_path_span.
 +    let span = path.span.with_hi(last_path_span.hi());
 +
 +    span_lint_and_sugg(
 +        cx,
 +        USE_SELF,
 +        span,
 +        "unnecessary structure name repetition",
 +        "use the applicable keyword",
 +        "Self".to_owned(),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +// FIXME: always use this (more correct) visitor, not just in method signatures.
 +struct SemanticUseSelfVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    self_ty: Ty<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
 +        if let TyKind::Path(QPath::Resolved(_, path)) = &hir_ty.kind {
 +            match path.res {
 +                def::Res::SelfTy(..) => {},
 +                _ => {
 +                    if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty {
 +                        span_use_self_lint(self.cx, path, None);
 +                    }
 +                },
 +            }
 +        }
 +
 +        walk_ty(self, hir_ty)
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn check_trait_method_impl_decl<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    impl_item: &ImplItem<'_>,
 +    impl_decl: &'tcx FnDecl<'_>,
 +    impl_trait_ref: ty::TraitRef<'tcx>,
 +) {
 +    let trait_method = cx
 +        .tcx
 +        .associated_items(impl_trait_ref.def_id)
 +        .find_by_name_and_kind(cx.tcx, impl_item.ident, ty::AssocKind::Fn, impl_trait_ref.def_id)
 +        .expect("impl method matches a trait method");
 +
 +    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
 +    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);
 +
 +    let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output {
 +        Some(&**ty)
 +    } else {
 +        None
 +    };
 +
 +    // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
 +    // `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait.
 +    // We use `impl_hir_ty` to see if the type was written as `Self`,
 +    // `hir_ty_to_ty(...)` to check semantic types of paths, and
 +    // `trait_ty` to determine which parts of the signature in the trait, mention
 +    // the type being implemented verbatim (as opposed to `Self`).
 +    for (impl_hir_ty, trait_ty) in impl_decl
 +        .inputs
 +        .iter()
 +        .chain(output_hir_ty)
 +        .zip(trait_method_sig.inputs_and_output)
 +    {
 +        // Check if the input/output type in the trait method specifies the implemented
 +        // type verbatim, and only suggest `Self` if that isn't the case.
 +        // This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`,
 +        // in an `impl Trait for u8`, when the trait always uses `Vec<u8>`.
 +        // See also https://github.com/rust-lang/rust-clippy/issues/2894.
 +        let self_ty = impl_trait_ref.self_ty();
 +        if !trait_ty.walk().any(|inner| inner == self_ty.into()) {
 +            let mut visitor = SemanticUseSelfVisitor { cx, self_ty };
 +
 +            visitor.visit_ty(&impl_hir_ty);
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for UseSelf {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if in_external_macro(cx.sess(), item.span) {
 +            return;
 +        }
 +        if_chain! {
 +            if let ItemKind::Impl{ self_ty: ref item_type, items: refs, .. } = item.kind;
 +            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind;
 +            then {
 +                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
 +                let should_check = parameters.as_ref().map_or(
 +                    true,
 +                    |params| !params.parenthesized
 +                        &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
 +                );
 +
 +                if should_check {
 +                    let visitor = &mut UseSelfVisitor {
 +                        item_path,
 +                        cx,
 +                    };
 +                    let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
 +                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);
 +
 +                    if let Some(impl_trait_ref) = impl_trait_ref {
 +                        for impl_item_ref in refs {
 +                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
 +                            if let ImplItemKind::Fn(FnSig{ decl: impl_decl, .. }, impl_body_id)
 +                                    = &impl_item.kind {
 +                                check_trait_method_impl_decl(cx, impl_item, impl_decl, impl_trait_ref);
 +
 +                                let body = cx.tcx.hir().body(*impl_body_id);
 +                                visitor.visit_body(body);
 +                            } else {
 +                                visitor.visit_impl_item(impl_item);
 +                            }
 +                        }
 +                    } else {
 +                        for impl_item_ref in refs {
 +                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
 +                            visitor.visit_impl_item(impl_item);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct UseSelfVisitor<'a, 'tcx> {
 +    item_path: &'a Path<'a>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
 +        if !path.segments.iter().any(|p| p.ident.span.is_dummy()) {
 +            if path.segments.len() >= 2 {
 +                let last_but_one = &path.segments[path.segments.len() - 2];
 +                if last_but_one.ident.name != kw::SelfUpper {
 +                    let enum_def_id = match path.res {
 +                        Res::Def(DefKind::Variant, variant_def_id) => self.cx.tcx.parent(variant_def_id),
 +                        Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), ctor_def_id) => {
 +                            let variant_def_id = self.cx.tcx.parent(ctor_def_id);
 +                            variant_def_id.and_then(|def_id| self.cx.tcx.parent(def_id))
 +                        },
 +                        _ => None,
 +                    };
 +
 +                    if self.item_path.res.opt_def_id() == enum_def_id {
 +                        span_use_self_lint(self.cx, path, Some(last_but_one));
 +                    }
 +                }
 +            }
 +
 +            if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
 +                if self.item_path.res == path.res {
 +                    span_use_self_lint(self.cx, path, None);
 +                } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), ctor_def_id) = path.res {
 +                    if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_def_id) {
 +                        span_use_self_lint(self.cx, path, None);
 +                    }
 +                }
 +            }
 +        }
 +
 +        walk_path(self, path);
 +    }
 +
 +    fn visit_item(&mut self, item: &'tcx Item<'_>) {
 +        match item.kind {
 +            ItemKind::Use(..)
 +            | ItemKind::Static(..)
 +            | ItemKind::Enum(..)
 +            | ItemKind::Struct(..)
 +            | ItemKind::Union(..)
 +            | ItemKind::Impl { .. }
 +            | ItemKind::Fn(..) => {
 +                // Don't check statements that shadow `Self` or where `Self` can't be used
 +            },
 +            _ => walk_item(self, item),
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +}
index 1bf37632e326cfa2d7a76be9361983a49fecd731,0000000000000000000000000000000000000000..4ab2b5e796deb75f7361fc466c9d69306e7c7db4
mode 100644,000000..100644
--- /dev/null
@@@ -1,188 -1,0 +1,189 @@@
-                                 let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
++use crate::utils::sugg::Sugg;
 +use crate::utils::{
 +    get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet,
 +    snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, TyS};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls
 +    /// that useless converts to the same type as caller.
 +    ///
 +    /// **Why is this bad?** Redundant code.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // Bad
 +    /// // format!() returns a `String`
 +    /// let s: String = format!("hello").into();
 +    ///
 +    /// // Good
 +    /// let s: String = format!("hello");
 +    /// ```
 +    pub USELESS_CONVERSION,
 +    complexity,
 +    "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type"
 +}
 +
 +#[derive(Default)]
 +pub struct UselessConversion {
 +    try_desugar_arm: Vec<HirId>,
 +}
 +
 +impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);
 +
 +#[allow(clippy::too_many_lines)]
 +impl<'tcx> LateLintPass<'tcx> for UselessConversion {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +
 +        if Some(&e.hir_id) == self.try_desugar_arm.last() {
 +            return;
 +        }
 +
 +        match e.kind {
 +            ExprKind::Match(_, ref arms, MatchSource::TryDesugar) => {
 +                let e = match arms[0].body.kind {
 +                    ExprKind::Ret(Some(ref e)) | ExprKind::Break(_, Some(ref e)) => e,
 +                    _ => return,
 +                };
 +                if let ExprKind::Call(_, ref args) = e.kind {
 +                    self.try_desugar_arm.push(args[0].hir_id);
 +                }
 +            },
 +
 +            ExprKind::MethodCall(ref name, .., ref args, _) => {
 +                if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
 +                    let a = cx.typeck_results().expr_ty(e);
 +                    let b = cx.typeck_results().expr_ty(&args[0]);
 +                    if TyS::same_type(a, b) {
 +                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
 +                        span_lint_and_sugg(
 +                            cx,
 +                            USELESS_CONVERSION,
 +                            e.span,
 +                            "useless conversion to the same type",
 +                            "consider removing `.into()`",
 +                            sugg,
 +                            Applicability::MachineApplicable, // snippet
 +                        );
 +                    }
 +                }
 +                if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
 +                    if let Some(parent_expr) = get_parent_expr(cx, e) {
 +                        if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
 +                            if &*parent_name.ident.as_str() != "into_iter" {
 +                                return;
 +                            }
 +                        }
 +                    }
 +                    let a = cx.typeck_results().expr_ty(e);
 +                    let b = cx.typeck_results().expr_ty(&args[0]);
 +                    if TyS::same_type(a, b) {
 +                        let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
 +                        span_lint_and_sugg(
 +                            cx,
 +                            USELESS_CONVERSION,
 +                            e.span,
 +                            "useless conversion to the same type",
 +                            "consider removing `.into_iter()`",
 +                            sugg,
 +                            Applicability::MachineApplicable, // snippet
 +                        );
 +                    }
 +                }
 +                if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
 +                    if_chain! {
 +                        let a = cx.typeck_results().expr_ty(e);
 +                        let b = cx.typeck_results().expr_ty(&args[0]);
 +                        if is_type_diagnostic_item(cx, a, sym!(result_type));
 +                        if let ty::Adt(_, substs) = a.kind;
 +                        if let Some(a_type) = substs.types().next();
 +                        if TyS::same_type(a_type, b);
 +
 +                        then {
 +                            span_lint_and_help(
 +                                cx,
 +                                USELESS_CONVERSION,
 +                                e.span,
 +                                "useless conversion to the same type",
 +                                None,
 +                                "consider removing `.try_into()`",
 +                            );
 +                        }
 +                    }
 +                }
 +            },
 +
 +            ExprKind::Call(ref path, ref args) => {
 +                if_chain! {
 +                    if args.len() == 1;
 +                    if let ExprKind::Path(ref qpath) = path.kind;
 +                    if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
 +                    let a = cx.typeck_results().expr_ty(e);
 +                    let b = cx.typeck_results().expr_ty(&args[0]);
 +
 +                    then {
 +                        if_chain! {
 +                            if match_def_path(cx, def_id, &paths::TRY_FROM);
 +                            if is_type_diagnostic_item(cx, a, sym!(result_type));
 +                            if let ty::Adt(_, substs) = a.kind;
 +                            if let Some(a_type) = substs.types().next();
 +                            if TyS::same_type(a_type, b);
 +
 +                            then {
 +                                let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
 +                                span_lint_and_help(
 +                                    cx,
 +                                    USELESS_CONVERSION,
 +                                    e.span,
 +                                    "useless conversion to the same type",
 +                                    None,
 +                                    &hint,
 +                                );
 +                            }
 +                        }
 +
 +                        if_chain! {
 +                            if match_def_path(cx, def_id, &paths::FROM_FROM);
 +                            if TyS::same_type(a, b);
 +
 +                            then {
-                                     sugg,
++                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
 +                                let sugg_msg =
 +                                    format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
 +                                span_lint_and_sugg(
 +                                    cx,
 +                                    USELESS_CONVERSION,
 +                                    e.span,
 +                                    "useless conversion to the same type",
 +                                    &sugg_msg,
++                                    sugg.to_string(),
 +                                    Applicability::MachineApplicable, // snippet
 +                                );
 +                            }
 +                        }
 +                    }
 +                }
 +            },
 +
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_expr_post(&mut self, _: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if Some(&e.hir_id) == self.try_desugar_arm.last() {
 +            self.try_desugar_arm.pop();
 +        }
 +    }
 +}
index c32c80dcd3ce6da1f31bdd87e6ddb7ca62948626,0000000000000000000000000000000000000000..7b419431c0f51dafe566ad6a29dd46394213ac74
mode 100644,000000..100644
--- /dev/null
@@@ -1,523 -1,0 +1,523 @@@
- use rustc_ast::{self as ast, *};
 +//! Utilities for manipulating and extracting information from `rustc_ast::ast`.
 +//!
 +//! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s.
 +
 +#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
 +
 +use crate::utils::{both, over};
 +use rustc_ast::ptr::P;
++use rustc_ast::{self as ast, *};
 +use rustc_span::symbol::Ident;
 +use std::mem;
 +
 +/// Checks if each element in the first slice is contained within the latter as per `eq_fn`.
 +pub fn unordered_over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
 +    left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r)))
 +}
 +
 +pub fn eq_id(l: Ident, r: Ident) -> bool {
 +    l.name == r.name
 +}
 +
 +pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
 +    use PatKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_pat(l, r),
 +        (_, Paren(r)) => eq_pat(l, r),
 +        (Wild, Wild) | (Rest, Rest) => true,
 +        (Lit(l), Lit(r)) => eq_expr(l, r),
 +        (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)),
 +        (Range(lf, lt, le), Range(rf, rt, re)) => {
 +            eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node)
 +        },
 +        (Box(l), Box(r))
 +        | (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
 +        | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
 +        (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
 +        (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
 +            lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
 +        },
 +        (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool {
 +    match (l, r) {
 +        (RangeEnd::Excluded, RangeEnd::Excluded) => true,
 +        (RangeEnd::Included(l), RangeEnd::Included(r)) => {
 +            matches!(l, RangeSyntax::DotDotEq) == matches!(r, RangeSyntax::DotDotEq)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_field_pat(l: &FieldPat, r: &FieldPat) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && eq_pat(&l.pat, &r.pat)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
 +    l.position == r.position && eq_ty(&l.ty, &r.ty)
 +}
 +
 +pub fn eq_path(l: &Path, r: &Path) -> bool {
 +    over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
 +}
 +
 +pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
 +    eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r))
 +}
 +
 +pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
 +    match (l, r) {
 +        (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => {
 +            over(&l.args, &r.args, |l, r| eq_angle_arg(l, r))
 +        },
 +        (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => {
 +            over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool {
 +    match (l, r) {
 +        (AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r),
 +        (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
 +    match (l, r) {
 +        (GenericArg::Lifetime(l), GenericArg::Lifetime(r)) => eq_id(l.ident, r.ident),
 +        (GenericArg::Type(l), GenericArg::Type(r)) => eq_ty(l, r),
 +        (GenericArg::Const(l), GenericArg::Const(r)) => eq_expr(&l.value, &r.value),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
 +    both(l, r, |l, r| eq_expr(l, r))
 +}
 +
 +pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
 +    use ExprKind::*;
 +    if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
 +        return false;
 +    }
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_expr(l, r),
 +        (_, Paren(r)) => eq_expr(l, r),
 +        (Err, Err) => true,
 +        (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
 +        (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
 +        (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
 +        (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
 +        (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
 +        (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
 +        (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
 +        (Lit(l), Lit(r)) => l.kind == r.kind,
 +        (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
 +        (Let(lp, le), Let(rp, re)) => eq_pat(lp, rp) && eq_expr(le, re),
 +        (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
 +        (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
 +        (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
 +            eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
 +        },
 +        (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt),
 +        (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
 +        (TryBlock(l), TryBlock(r)) => eq_block(l, r),
 +        (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
 +        (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
 +        (Continue(ll), Continue(rl)) => eq_label(ll, rl),
 +        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
 +        (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
 +        (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
 +        (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)),
 +        (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
 +            lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
 +        },
 +        (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
 +        (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
 +        (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        (Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
 +            eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_field(l: &Field, r: &Field) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && eq_expr(&l.expr, &r.expr)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_pat(&l.pat, &r.pat)
 +        && eq_expr(&l.body, &r.body)
 +        && eq_expr_opt(&l.guard, &r.guard)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
 +    both(l, r, |l, r| eq_id(l.ident, r.ident))
 +}
 +
 +pub fn eq_block(l: &Block, r: &Block) -> bool {
 +    l.rules == r.rules && over(&l.stmts, &r.stmts, |l, r| eq_stmt(l, r))
 +}
 +
 +pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
 +    use StmtKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Local(l), Local(r)) => {
 +            eq_pat(&l.pat, &r.pat)
 +                && both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
 +                && eq_expr_opt(&l.init, &r.init)
 +                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        },
 +        (Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
 +        (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
 +        (Empty, Empty) => true,
 +        (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool {
 +    eq_id(l.ident, r.ident)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && eq_kind(&l.kind, &r.kind)
 +}
 +
 +pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
 +    use ItemKind::*;
 +    match (l, r) {
 +        (ExternCrate(l), ExternCrate(r)) => l == r,
 +        (Use(l), Use(r)) => eq_use_tree(l, r),
 +        (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
 +        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
 +        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
 +            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
 +        },
 +        (Mod(l), Mod(r)) => l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind)),
 +        (ForeignMod(l), ForeignMod(r)) => {
 +            both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
 +                && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
 +        },
 +        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (Enum(le, lg), Enum(re, rg)) => {
 +            over(&le.variants, &re.variants, |l, r| eq_variant(l, r)) && eq_generics(lg, rg)
 +        },
 +        (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
 +            eq_variant_data(lv, rv) && eq_generics(lg, rg)
 +        },
 +        (Trait(la, lu, lg, lb, li), Trait(ra, ru, rg, rb, ri)) => {
 +            la == ra
 +                && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
 +        },
 +        (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, |l, r| eq_generic_bound(l, r)),
 +        (
 +            Impl {
 +                unsafety: lu,
 +                polarity: lp,
 +                defaultness: ld,
 +                constness: lc,
 +                generics: lg,
 +                of_trait: lot,
 +                self_ty: lst,
 +                items: li,
 +            },
 +            Impl {
 +                unsafety: ru,
 +                polarity: rp,
 +                defaultness: rd,
 +                constness: rc,
 +                generics: rg,
 +                of_trait: rot,
 +                self_ty: rst,
 +                items: ri,
 +            },
 +        ) => {
 +            matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
 +                && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
 +                && eq_defaultness(*ld, *rd)
 +                && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
 +                && eq_generics(lg, rg)
 +                && both(lot, rot, |l, r| eq_path(&l.path, &r.path))
 +                && eq_ty(lst, rst)
 +                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_mac_args(&l.body, &r.body),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
 +    use ForeignItemKind::*;
 +    match (l, r) {
 +        (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
 +        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
 +            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
 +        },
 +        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
 +    use AssocItemKind::*;
 +    match (l, r) {
 +        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
 +        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
 +            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
 +        },
 +        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && eq_id(l.ident, r.ident)
 +        && eq_variant_data(&l.data, &r.data)
 +        && both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value))
 +}
 +
 +pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
 +    use VariantData::*;
 +    match (l, r) {
 +        (Unit(_), Unit(_)) => true,
 +        (Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, |l, r| eq_struct_field(l, r)),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_struct_field(l: &StructField, r: &StructField) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
 +        && eq_ty(&l.ty, &r.ty)
 +}
 +
 +pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
 +    eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header)
 +}
 +
 +pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
 +    matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
 +        && l.asyncness.is_async() == r.asyncness.is_async()
 +        && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
 +        && eq_ext(&l.ext, &r.ext)
 +}
 +
 +pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
 +    over(&l.params, &r.params, |l, r| eq_generic_param(l, r))
 +        && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
 +            eq_where_predicate(l, r)
 +        })
 +}
 +
 +pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
 +    use WherePredicate::*;
 +    match (l, r) {
 +        (BoundPredicate(l), BoundPredicate(r)) => {
 +            over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
 +                eq_generic_param(l, r)
 +            }) && eq_ty(&l.bounded_ty, &r.bounded_ty)
 +                && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        },
 +        (RegionPredicate(l), RegionPredicate(r)) => {
 +            eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        },
 +        (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool {
 +    eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind)
 +}
 +
 +pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
 +    use UseTreeKind::*;
 +    match (l, r) {
 +        (Glob, Glob) => true,
 +        (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)),
 +        (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
 +    matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)))
 +}
 +
 +pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
 +    use VisibilityKind::*;
 +    match (&l.node, &r.node) {
 +        (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true,
 +        (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
 +    eq_fn_ret_ty(&l.output, &r.output)
 +        && over(&l.inputs, &r.inputs, |l, r| {
 +            l.is_placeholder == r.is_placeholder
 +                && eq_pat(&l.pat, &r.pat)
 +                && eq_ty(&l.ty, &r.ty)
 +                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        })
 +}
 +
 +pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool {
 +    match (l, r) {
 +        (FnRetTy::Default(_), FnRetTy::Default(_)) => true,
 +        (FnRetTy::Ty(l), FnRetTy::Ty(r)) => eq_ty(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
 +    use TyKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_ty(l, r),
 +        (_, Paren(r)) => eq_ty(l, r),
 +        (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true,
 +        (Slice(l), Slice(r)) => eq_ty(l, r),
 +        (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
 +        (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
 +        (Rptr(ll, l), Rptr(rl, r)) => {
 +            both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
 +        },
 +        (BareFn(l), BareFn(r)) => {
 +            l.unsafety == r.unsafety
 +                && eq_ext(&l.ext, &r.ext)
 +                && over(&l.generic_params, &r.generic_params, |l, r| eq_generic_param(l, r))
 +                && eq_fn_decl(&l.decl, &r.decl)
 +        },
 +        (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, |l, r| eq_generic_bound(l, r)),
 +        (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, |l, r| eq_generic_bound(l, r)),
 +        (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_ext(l: &Extern, r: &Extern) -> bool {
 +    use Extern::*;
 +    match (l, r) {
 +        (None, None) | (Implicit, Implicit) => true,
 +        (Explicit(l), Explicit(r)) => eq_str_lit(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_str_lit(l: &StrLit, r: &StrLit) -> bool {
 +    l.style == r.style && l.symbol == r.symbol && l.suffix == r.suffix
 +}
 +
 +pub fn eq_poly_ref_trait(l: &PolyTraitRef, r: &PolyTraitRef) -> bool {
 +    eq_path(&l.trait_ref.path, &r.trait_ref.path)
 +        && over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
 +            eq_generic_param(l, r)
 +        })
 +}
 +
 +pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
 +    use GenericParamKind::*;
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        && match (&l.kind, &r.kind) {
 +            (Lifetime, Lifetime) => true,
 +            (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
 +            (Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r),
 +            _ => false,
 +        }
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
 +    use GenericBound::*;
 +    match (l, r) {
 +        (Trait(ptr1, tbm1), Trait(ptr2, tbm2)) => tbm1 == tbm2 && eq_poly_ref_trait(ptr1, ptr2),
 +        (Outlives(l), Outlives(r)) => eq_id(l.ident, r.ident),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
 +    use AssocTyConstraintKind::*;
 +    eq_id(l.ident, r.ident)
 +        && match (&l.kind, &r.kind) {
 +            (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
 +            (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, |l, r| eq_generic_bound(l, r)),
 +            _ => false,
 +        }
 +}
 +
 +pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool {
 +    eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args)
 +}
 +
 +pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
 +    use AttrKind::*;
 +    l.style == r.style
 +        && match (&l.kind, &r.kind) {
 +            (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
 +            (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
 +            _ => false,
 +        }
 +}
 +
 +pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
 +    use MacArgs::*;
 +    match (l, r) {
 +        (Empty, Empty) => true,
 +        (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts),
 +        (Eq(_, lts), Eq(_, rts)) => lts.eq_unspanned(rts),
 +        _ => false,
 +    }
 +}
index 9b7a268c6287c1fffd8b2fab131bb2d53bbeb175,0000000000000000000000000000000000000000..6eda6d1fa834074abca08450b2ece236c44ba175
mode 100644,000000..100644
--- /dev/null
@@@ -1,775 -1,0 +1,772 @@@
-         match  *path {
-             QPath::LangItem(lang_item, _) => {
-                 println!(
-                     "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
-                    self.current, lang_item,
-                 );
-             },
-             _ => {
-                 print!("    if match_qpath({}, &[", self.current);
-                 print_path(path, &mut true);
-                 println!("]);");
-             },
 +//! A group of attributes that can be attached to Rust code in order
 +//! to generate a clippy lint detecting said code automatically.
 +
 +use crate::utils::{get_attr, higher};
 +use rustc_ast::ast::{Attribute, LitFloatType, LitKind};
 +use rustc_ast::walk_list;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::Session;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Generates clippy code that detects the offending pattern
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// // ./tests/ui/my_lint.rs
 +    /// fn foo() {
 +    ///     // detect the following pattern
 +    ///     #[clippy::author]
 +    ///     if x == 42 {
 +    ///         // but ignore everything from here on
 +    ///         #![clippy::author = "ignore"]
 +    ///     }
 +    ///     ()
 +    /// }
 +    /// ```
 +    ///
 +    /// Running `TESTNAME=ui/my_lint cargo uitest` will produce
 +    /// a `./tests/ui/new_lint.stdout` file with the generated code:
 +    ///
 +    /// ```rust,ignore
 +    /// // ./tests/ui/new_lint.stdout
 +    /// if_chain! {
 +    ///     if let ExprKind::If(ref cond, ref then, None) = item.kind,
 +    ///     if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind,
 +    ///     if let ExprKind::Path(ref path) = left.kind,
 +    ///     if let ExprKind::Lit(ref lit) = right.kind,
 +    ///     if let LitKind::Int(42, _) = lit.node,
 +    ///     then {
 +    ///         // report your lint here
 +    ///     }
 +    /// }
 +    /// ```
 +    pub LINT_AUTHOR,
 +    internal_warn,
 +    "helper for writing lints"
 +}
 +
 +declare_lint_pass!(Author => [LINT_AUTHOR]);
 +
 +fn prelude() {
 +    println!("if_chain! {{");
 +}
 +
 +fn done() {
 +    println!("    then {{");
 +    println!("        // report your lint here");
 +    println!("    }}");
 +    println!("}}");
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Author {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        if !has_attr(cx.sess(), &item.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("item").visit_item(item);
 +        done();
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
 +        if !has_attr(cx.sess(), &item.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("item").visit_impl_item(item);
 +        done();
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
 +        if !has_attr(cx.sess(), &item.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("item").visit_trait_item(item);
 +        done();
 +    }
 +
 +    fn check_variant(&mut self, cx: &LateContext<'tcx>, var: &'tcx hir::Variant<'_>) {
 +        if !has_attr(cx.sess(), &var.attrs) {
 +            return;
 +        }
 +        prelude();
 +        let parent_hir_id = cx.tcx.hir().get_parent_node(var.id);
 +        PrintVisitor::new("var").visit_variant(var, &hir::Generics::empty(), parent_hir_id);
 +        done();
 +    }
 +
 +    fn check_struct_field(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::StructField<'_>) {
 +        if !has_attr(cx.sess(), &field.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("field").visit_struct_field(field);
 +        done();
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if !has_attr(cx.sess(), &expr.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("expr").visit_expr(expr);
 +        done();
 +    }
 +
 +    fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
 +        if !has_attr(cx.sess(), &arm.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("arm").visit_arm(arm);
 +        done();
 +    }
 +
 +    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
 +        if !has_attr(cx.sess(), stmt.kind.attrs()) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("stmt").visit_stmt(stmt);
 +        done();
 +    }
 +
 +    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'_>) {
 +        if !has_attr(cx.sess(), &item.attrs) {
 +            return;
 +        }
 +        prelude();
 +        PrintVisitor::new("item").visit_foreign_item(item);
 +        done();
 +    }
 +}
 +
 +impl PrintVisitor {
 +    #[must_use]
 +    fn new(s: &'static str) -> Self {
 +        Self {
 +            ids: FxHashMap::default(),
 +            current: s.to_owned(),
 +        }
 +    }
 +
 +    fn next(&mut self, s: &'static str) -> String {
 +        use std::collections::hash_map::Entry::{Occupied, Vacant};
 +        match self.ids.entry(s) {
 +            // already there: start numbering from `1`
 +            Occupied(mut occ) => {
 +                let val = occ.get_mut();
 +                *val += 1;
 +                format!("{}{}", s, *val)
 +            },
 +            // not there: insert and return name as given
 +            Vacant(vac) => {
 +                vac.insert(0);
 +                s.to_owned()
 +            },
 +        }
 +    }
 +
 +    fn print_qpath(&mut self, path: &QPath<'_>) {
++        if let QPath::LangItem(lang_item, _) = *path {
++            println!(
++                "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
++                self.current, lang_item,
++            );
++        } else {
++            print!("    if match_qpath({}, &[", self.current);
++            print_path(path, &mut true);
++            println!("]);");
 +        }
 +    }
 +}
 +
 +struct PrintVisitor {
 +    /// Fields are the current index that needs to be appended to pattern
 +    /// binding names
 +    ids: FxHashMap<&'static str, usize>,
 +    /// the name that needs to be destructured
 +    current: String,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for PrintVisitor {
 +    type Map = Map<'tcx>;
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn visit_expr(&mut self, expr: &Expr<'_>) {
 +        // handle if desugarings
 +        // TODO add more desugarings here
 +        if let Some((cond, then, opt_else)) = higher::if_block(&expr) {
 +            let cond_pat = self.next("cond");
 +            let then_pat = self.next("then");
 +            if let Some(else_) = opt_else {
 +                let else_pat = self.next("else_");
 +                println!(
 +                    "    if let Some((ref {}, ref {}, Some({}))) = higher::if_block(&{});",
 +                    cond_pat, then_pat, else_pat, self.current
 +                );
 +                self.current = else_pat;
 +                self.visit_expr(else_);
 +            } else {
 +                println!(
 +                    "    if let Some((ref {}, ref {}, None)) = higher::if_block(&{});",
 +                    cond_pat, then_pat, self.current
 +                );
 +            }
 +            self.current = cond_pat;
 +            self.visit_expr(cond);
 +            self.current = then_pat;
 +            self.visit_expr(then);
 +            return;
 +        }
 +
 +        print!("    if let ExprKind::");
 +        let current = format!("{}.kind", self.current);
 +        match expr.kind {
 +            ExprKind::Box(ref inner) => {
 +                let inner_pat = self.next("inner");
 +                println!("Box(ref {}) = {};", inner_pat, current);
 +                self.current = inner_pat;
 +                self.visit_expr(inner);
 +            },
 +            ExprKind::Array(ref elements) => {
 +                let elements_pat = self.next("elements");
 +                println!("Array(ref {}) = {};", elements_pat, current);
 +                println!("    if {}.len() == {};", elements_pat, elements.len());
 +                for (i, element) in elements.iter().enumerate() {
 +                    self.current = format!("{}[{}]", elements_pat, i);
 +                    self.visit_expr(element);
 +                }
 +            },
 +            ExprKind::Call(ref func, ref args) => {
 +                let func_pat = self.next("func");
 +                let args_pat = self.next("args");
 +                println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current);
 +                self.current = func_pat;
 +                self.visit_expr(func);
 +                println!("    if {}.len() == {};", args_pat, args.len());
 +                for (i, arg) in args.iter().enumerate() {
 +                    self.current = format!("{}[{}]", args_pat, i);
 +                    self.visit_expr(arg);
 +                }
 +            },
 +            ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
 +                println!(
 +                    "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
 +                    current
 +                );
 +                println!("    // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
 +            },
 +            ExprKind::Tup(ref elements) => {
 +                let elements_pat = self.next("elements");
 +                println!("Tup(ref {}) = {};", elements_pat, current);
 +                println!("    if {}.len() == {};", elements_pat, elements.len());
 +                for (i, element) in elements.iter().enumerate() {
 +                    self.current = format!("{}[{}]", elements_pat, i);
 +                    self.visit_expr(element);
 +                }
 +            },
 +            ExprKind::Binary(ref op, ref left, ref right) => {
 +                let op_pat = self.next("op");
 +                let left_pat = self.next("left");
 +                let right_pat = self.next("right");
 +                println!(
 +                    "Binary(ref {}, ref {}, ref {}) = {};",
 +                    op_pat, left_pat, right_pat, current
 +                );
 +                println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
 +                self.current = left_pat;
 +                self.visit_expr(left);
 +                self.current = right_pat;
 +                self.visit_expr(right);
 +            },
 +            ExprKind::Unary(ref op, ref inner) => {
 +                let inner_pat = self.next("inner");
 +                println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current);
 +                self.current = inner_pat;
 +                self.visit_expr(inner);
 +            },
 +            ExprKind::Lit(ref lit) => {
 +                let lit_pat = self.next("lit");
 +                println!("Lit(ref {}) = {};", lit_pat, current);
 +                match lit.node {
 +                    LitKind::Bool(val) => println!("    if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
 +                    LitKind::Char(c) => println!("    if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
 +                    LitKind::Err(val) => println!("    if let LitKind::Err({}) = {}.node;", val, lit_pat),
 +                    LitKind::Byte(b) => println!("    if let LitKind::Byte({}) = {}.node;", b, lit_pat),
 +                    // FIXME: also check int type
 +                    LitKind::Int(i, _) => println!("    if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
 +                    LitKind::Float(_, LitFloatType::Suffixed(_)) => println!(
 +                        "    if let LitKind::Float(_, LitFloatType::Suffixed(_)) = {}.node;",
 +                        lit_pat
 +                    ),
 +                    LitKind::Float(_, LitFloatType::Unsuffixed) => println!(
 +                        "    if let LitKind::Float(_, LitFloatType::Unsuffixed) = {}.node;",
 +                        lit_pat
 +                    ),
 +                    LitKind::ByteStr(ref vec) => {
 +                        let vec_pat = self.next("vec");
 +                        println!("    if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
 +                        println!("    if let [{:?}] = **{};", vec, vec_pat);
 +                    },
 +                    LitKind::Str(ref text, _) => {
 +                        let str_pat = self.next("s");
 +                        println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
 +                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str())
 +                    },
 +                }
 +            },
 +            ExprKind::Cast(ref expr, ref ty) => {
 +                let cast_pat = self.next("expr");
 +                let cast_ty = self.next("cast_ty");
 +                let qp_label = self.next("qp");
 +
 +                println!("Cast(ref {}, ref {}) = {};", cast_pat, cast_ty, current);
 +                if let TyKind::Path(ref qp) = ty.kind {
 +                    println!("    if let TyKind::Path(ref {}) = {}.kind;", qp_label, cast_ty);
 +                    self.current = qp_label;
 +                    self.print_qpath(qp);
 +                }
 +                self.current = cast_pat;
 +                self.visit_expr(expr);
 +            },
 +            ExprKind::Type(ref expr, ref _ty) => {
 +                let cast_pat = self.next("expr");
 +                println!("Type(ref {}, _) = {};", cast_pat, current);
 +                self.current = cast_pat;
 +                self.visit_expr(expr);
 +            },
 +            ExprKind::Loop(ref body, _, desugaring) => {
 +                let body_pat = self.next("body");
 +                let des = loop_desugaring_name(desugaring);
 +                let label_pat = self.next("label");
 +                println!("Loop(ref {}, ref {}, {}) = {};", body_pat, label_pat, des, current);
 +                self.current = body_pat;
 +                self.visit_block(body);
 +            },
 +            ExprKind::Match(ref expr, ref arms, desugaring) => {
 +                let des = desugaring_name(desugaring);
 +                let expr_pat = self.next("expr");
 +                let arms_pat = self.next("arms");
 +                println!("Match(ref {}, ref {}, {}) = {};", expr_pat, arms_pat, des, current);
 +                self.current = expr_pat;
 +                self.visit_expr(expr);
 +                println!("    if {}.len() == {};", arms_pat, arms.len());
 +                for (i, arm) in arms.iter().enumerate() {
 +                    self.current = format!("{}[{}].body", arms_pat, i);
 +                    self.visit_expr(&arm.body);
 +                    if let Some(ref guard) = arm.guard {
 +                        let guard_pat = self.next("guard");
 +                        println!("    if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
 +                        match guard {
 +                            hir::Guard::If(ref if_expr) => {
 +                                let if_expr_pat = self.next("expr");
 +                                println!("    if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
 +                                self.current = if_expr_pat;
 +                                self.visit_expr(if_expr);
 +                            },
 +                        }
 +                    }
 +                    self.current = format!("{}[{}].pat", arms_pat, i);
 +                    self.visit_pat(&arm.pat);
 +                }
 +            },
 +            ExprKind::Closure(ref _capture_clause, ref _func, _, _, _) => {
 +                println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current);
 +                println!("    // unimplemented: `ExprKind::Closure` is not further destructured at the moment");
 +            },
 +            ExprKind::Yield(ref sub, _) => {
 +                let sub_pat = self.next("sub");
 +                println!("Yield(ref sub) = {};", current);
 +                self.current = sub_pat;
 +                self.visit_expr(sub);
 +            },
 +            ExprKind::Block(ref block, _) => {
 +                let block_pat = self.next("block");
 +                println!("Block(ref {}) = {};", block_pat, current);
 +                self.current = block_pat;
 +                self.visit_block(block);
 +            },
 +            ExprKind::Assign(ref target, ref value, _) => {
 +                let target_pat = self.next("target");
 +                let value_pat = self.next("value");
 +                println!(
 +                    "Assign(ref {}, ref {}, ref _span) = {};",
 +                    target_pat, value_pat, current
 +                );
 +                self.current = target_pat;
 +                self.visit_expr(target);
 +                self.current = value_pat;
 +                self.visit_expr(value);
 +            },
 +            ExprKind::AssignOp(ref op, ref target, ref value) => {
 +                let op_pat = self.next("op");
 +                let target_pat = self.next("target");
 +                let value_pat = self.next("value");
 +                println!(
 +                    "AssignOp(ref {}, ref {}, ref {}) = {};",
 +                    op_pat, target_pat, value_pat, current
 +                );
 +                println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
 +                self.current = target_pat;
 +                self.visit_expr(target);
 +                self.current = value_pat;
 +                self.visit_expr(value);
 +            },
 +            ExprKind::Field(ref object, ref field_ident) => {
 +                let obj_pat = self.next("object");
 +                let field_name_pat = self.next("field_name");
 +                println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current);
 +                println!("    if {}.as_str() == {:?}", field_name_pat, field_ident.as_str());
 +                self.current = obj_pat;
 +                self.visit_expr(object);
 +            },
 +            ExprKind::Index(ref object, ref index) => {
 +                let object_pat = self.next("object");
 +                let index_pat = self.next("index");
 +                println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current);
 +                self.current = object_pat;
 +                self.visit_expr(object);
 +                self.current = index_pat;
 +                self.visit_expr(index);
 +            },
 +            ExprKind::Path(ref path) => {
 +                let path_pat = self.next("path");
 +                println!("Path(ref {}) = {};", path_pat, current);
 +                self.current = path_pat;
 +                self.print_qpath(path);
 +            },
 +            ExprKind::AddrOf(kind, mutability, ref inner) => {
 +                let inner_pat = self.next("inner");
 +                println!(
 +                    "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};",
 +                    kind, mutability, inner_pat, current
 +                );
 +                self.current = inner_pat;
 +                self.visit_expr(inner);
 +            },
 +            ExprKind::Break(ref _destination, ref opt_value) => {
 +                let destination_pat = self.next("destination");
 +                if let Some(ref value) = *opt_value {
 +                    let value_pat = self.next("value");
 +                    println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current);
 +                    self.current = value_pat;
 +                    self.visit_expr(value);
 +                } else {
 +                    println!("Break(ref {}, None) = {};", destination_pat, current);
 +                }
 +                // FIXME: implement label printing
 +            },
 +            ExprKind::Continue(ref _destination) => {
 +                let destination_pat = self.next("destination");
 +                println!("Again(ref {}) = {};", destination_pat, current);
 +                // FIXME: implement label printing
 +            },
 +            ExprKind::Ret(ref opt_value) => {
 +                if let Some(ref value) = *opt_value {
 +                    let value_pat = self.next("value");
 +                    println!("Ret(Some(ref {})) = {};", value_pat, current);
 +                    self.current = value_pat;
 +                    self.visit_expr(value);
 +                } else {
 +                    println!("Ret(None) = {};", current);
 +                }
 +            },
 +            ExprKind::InlineAsm(_) => {
 +                println!("InlineAsm(_) = {};", current);
 +                println!("    // unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
 +            },
 +            ExprKind::LlvmInlineAsm(_) => {
 +                println!("LlvmInlineAsm(_) = {};", current);
 +                println!("    // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
 +            },
 +            ExprKind::Struct(ref path, ref fields, ref opt_base) => {
 +                let path_pat = self.next("path");
 +                let fields_pat = self.next("fields");
 +                if let Some(ref base) = *opt_base {
 +                    let base_pat = self.next("base");
 +                    println!(
 +                        "Struct(ref {}, ref {}, Some(ref {})) = {};",
 +                        path_pat, fields_pat, base_pat, current
 +                    );
 +                    self.current = base_pat;
 +                    self.visit_expr(base);
 +                } else {
 +                    println!("Struct(ref {}, ref {}, None) = {};", path_pat, fields_pat, current);
 +                }
 +                self.current = path_pat;
 +                self.print_qpath(path);
 +                println!("    if {}.len() == {};", fields_pat, fields.len());
 +                println!("    // unimplemented: field checks");
 +            },
 +            // FIXME: compute length (needs type info)
 +            ExprKind::Repeat(ref value, _) => {
 +                let value_pat = self.next("value");
 +                println!("Repeat(ref {}, _) = {};", value_pat, current);
 +                println!("// unimplemented: repeat count check");
 +                self.current = value_pat;
 +                self.visit_expr(value);
 +            },
 +            ExprKind::Err => {
 +                println!("Err = {}", current);
 +            },
 +            ExprKind::DropTemps(ref expr) => {
 +                let expr_pat = self.next("expr");
 +                println!("DropTemps(ref {}) = {};", expr_pat, current);
 +                self.current = expr_pat;
 +                self.visit_expr(expr);
 +            },
 +        }
 +    }
 +
 +    fn visit_block(&mut self, block: &Block<'_>) {
 +        let trailing_pat = self.next("trailing_expr");
 +        println!("    if let Some({}) = &{}.expr;", trailing_pat, self.current);
 +        println!("    if {}.stmts.len() == {};", self.current, block.stmts.len());
 +        let current = self.current.clone();
 +        for (i, stmt) in block.stmts.iter().enumerate() {
 +            self.current = format!("{}.stmts[{}]", current, i);
 +            self.visit_stmt(stmt);
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn visit_pat(&mut self, pat: &Pat<'_>) {
 +        print!("    if let PatKind::");
 +        let current = format!("{}.kind", self.current);
 +        match pat.kind {
 +            PatKind::Wild => println!("Wild = {};", current),
 +            PatKind::Binding(anno, .., ident, ref sub) => {
 +                let anno_pat = match anno {
 +                    BindingAnnotation::Unannotated => "BindingAnnotation::Unannotated",
 +                    BindingAnnotation::Mutable => "BindingAnnotation::Mutable",
 +                    BindingAnnotation::Ref => "BindingAnnotation::Ref",
 +                    BindingAnnotation::RefMut => "BindingAnnotation::RefMut",
 +                };
 +                let name_pat = self.next("name");
 +                if let Some(ref sub) = *sub {
 +                    let sub_pat = self.next("sub");
 +                    println!(
 +                        "Binding({}, _, {}, Some(ref {})) = {};",
 +                        anno_pat, name_pat, sub_pat, current
 +                    );
 +                    self.current = sub_pat;
 +                    self.visit_pat(sub);
 +                } else {
 +                    println!("Binding({}, _, {}, None) = {};", anno_pat, name_pat, current);
 +                }
 +                println!("    if {}.as_str() == \"{}\";", name_pat, ident.as_str());
 +            },
 +            PatKind::Struct(ref path, ref fields, ignore) => {
 +                let path_pat = self.next("path");
 +                let fields_pat = self.next("fields");
 +                println!(
 +                    "Struct(ref {}, ref {}, {}) = {};",
 +                    path_pat, fields_pat, ignore, current
 +                );
 +                self.current = path_pat;
 +                self.print_qpath(path);
 +                println!("    if {}.len() == {};", fields_pat, fields.len());
 +                println!("    // unimplemented: field checks");
 +            },
 +            PatKind::Or(ref fields) => {
 +                let fields_pat = self.next("fields");
 +                println!("Or(ref {}) = {};", fields_pat, current);
 +                println!("    if {}.len() == {};", fields_pat, fields.len());
 +                println!("    // unimplemented: field checks");
 +            },
 +            PatKind::TupleStruct(ref path, ref fields, skip_pos) => {
 +                let path_pat = self.next("path");
 +                let fields_pat = self.next("fields");
 +                println!(
 +                    "TupleStruct(ref {}, ref {}, {:?}) = {};",
 +                    path_pat, fields_pat, skip_pos, current
 +                );
 +                self.current = path_pat;
 +                self.print_qpath(path);
 +                println!("    if {}.len() == {};", fields_pat, fields.len());
 +                println!("    // unimplemented: field checks");
 +            },
 +            PatKind::Path(ref path) => {
 +                let path_pat = self.next("path");
 +                println!("Path(ref {}) = {};", path_pat, current);
 +                self.current = path_pat;
 +                self.print_qpath(path);
 +            },
 +            PatKind::Tuple(ref fields, skip_pos) => {
 +                let fields_pat = self.next("fields");
 +                println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
 +                println!("    if {}.len() == {};", fields_pat, fields.len());
 +                println!("    // unimplemented: field checks");
 +            },
 +            PatKind::Box(ref pat) => {
 +                let pat_pat = self.next("pat");
 +                println!("Box(ref {}) = {};", pat_pat, current);
 +                self.current = pat_pat;
 +                self.visit_pat(pat);
 +            },
 +            PatKind::Ref(ref pat, muta) => {
 +                let pat_pat = self.next("pat");
 +                println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current);
 +                self.current = pat_pat;
 +                self.visit_pat(pat);
 +            },
 +            PatKind::Lit(ref lit_expr) => {
 +                let lit_expr_pat = self.next("lit_expr");
 +                println!("Lit(ref {}) = {}", lit_expr_pat, current);
 +                self.current = lit_expr_pat;
 +                self.visit_expr(lit_expr);
 +            },
 +            PatKind::Range(ref start, ref end, end_kind) => {
 +                let start_pat = self.next("start");
 +                let end_pat = self.next("end");
 +                println!(
 +                    "Range(ref {}, ref {}, RangeEnd::{:?}) = {};",
 +                    start_pat, end_pat, end_kind, current
 +                );
 +                self.current = start_pat;
 +                walk_list!(self, visit_expr, start);
 +                self.current = end_pat;
 +                walk_list!(self, visit_expr, end);
 +            },
 +            PatKind::Slice(ref start, ref middle, ref end) => {
 +                let start_pat = self.next("start");
 +                let end_pat = self.next("end");
 +                if let Some(ref middle) = middle {
 +                    let middle_pat = self.next("middle");
 +                    println!(
 +                        "Slice(ref {}, Some(ref {}), ref {}) = {};",
 +                        start_pat, middle_pat, end_pat, current
 +                    );
 +                    self.current = middle_pat;
 +                    self.visit_pat(middle);
 +                } else {
 +                    println!("Slice(ref {}, None, ref {}) = {};", start_pat, end_pat, current);
 +                }
 +                println!("    if {}.len() == {};", start_pat, start.len());
 +                for (i, pat) in start.iter().enumerate() {
 +                    self.current = format!("{}[{}]", start_pat, i);
 +                    self.visit_pat(pat);
 +                }
 +                println!("    if {}.len() == {};", end_pat, end.len());
 +                for (i, pat) in end.iter().enumerate() {
 +                    self.current = format!("{}[{}]", end_pat, i);
 +                    self.visit_pat(pat);
 +                }
 +            },
 +        }
 +    }
 +
 +    fn visit_stmt(&mut self, s: &Stmt<'_>) {
 +        print!("    if let StmtKind::");
 +        let current = format!("{}.kind", self.current);
 +        match s.kind {
 +            // A local (let) binding:
 +            StmtKind::Local(ref local) => {
 +                let local_pat = self.next("local");
 +                println!("Local(ref {}) = {};", local_pat, current);
 +                if let Some(ref init) = local.init {
 +                    let init_pat = self.next("init");
 +                    println!("    if let Some(ref {}) = {}.init;", init_pat, local_pat);
 +                    self.current = init_pat;
 +                    self.visit_expr(init);
 +                }
 +                self.current = format!("{}.pat", local_pat);
 +                self.visit_pat(&local.pat);
 +            },
 +            // An item binding:
 +            StmtKind::Item(_) => {
 +                println!("Item(item_id) = {};", current);
 +            },
 +
 +            // Expr without trailing semi-colon (must have unit type):
 +            StmtKind::Expr(ref e) => {
 +                let e_pat = self.next("e");
 +                println!("Expr(ref {}, _) = {}", e_pat, current);
 +                self.current = e_pat;
 +                self.visit_expr(e);
 +            },
 +
 +            // Expr with trailing semi-colon (may have any type):
 +            StmtKind::Semi(ref e) => {
 +                let e_pat = self.next("e");
 +                println!("Semi(ref {}, _) = {}", e_pat, current);
 +                self.current = e_pat;
 +                self.visit_expr(e);
 +            },
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
 +    get_attr(sess, attrs, "author").count() > 0
 +}
 +
 +#[must_use]
 +fn desugaring_name(des: hir::MatchSource) -> String {
 +    match des {
 +        hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(),
 +        hir::MatchSource::TryDesugar => "MatchSource::TryDesugar".to_string(),
 +        hir::MatchSource::WhileDesugar => "MatchSource::WhileDesugar".to_string(),
 +        hir::MatchSource::WhileLetDesugar => "MatchSource::WhileLetDesugar".to_string(),
 +        hir::MatchSource::Normal => "MatchSource::Normal".to_string(),
 +        hir::MatchSource::IfLetDesugar { contains_else_clause } => format!(
 +            "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}",
 +            contains_else_clause
 +        ),
 +        hir::MatchSource::IfDesugar { contains_else_clause } => format!(
 +            "MatchSource::IfDesugar {{ contains_else_clause: {} }}",
 +            contains_else_clause
 +        ),
 +        hir::MatchSource::AwaitDesugar => "MatchSource::AwaitDesugar".to_string(),
 +    }
 +}
 +
 +#[must_use]
 +fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
 +    match des {
 +        hir::LoopSource::ForLoop => "LoopSource::ForLoop",
 +        hir::LoopSource::Loop => "LoopSource::Loop",
 +        hir::LoopSource::While => "LoopSource::While",
 +        hir::LoopSource::WhileLet => "LoopSource::WhileLet",
 +    }
 +}
 +
 +fn print_path(path: &QPath<'_>, first: &mut bool) {
 +    match *path {
 +        QPath::Resolved(_, ref path) => {
 +            for segment in path.segments {
 +                if *first {
 +                    *first = false;
 +                } else {
 +                    print!(", ");
 +                }
 +                print!("{:?}", segment.ident.as_str());
 +            }
 +        },
 +        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
 +            hir::TyKind::Path(ref inner_path) => {
 +                print_path(inner_path, first);
 +                if *first {
 +                    *first = false;
 +                } else {
 +                    print!(", ");
 +                }
 +                print!("{:?}", segment.ident.as_str());
 +            },
 +            ref other => print!("/* unimplemented: {:?}*/", other),
 +        },
 +        QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
 +    }
 +}
index ba3492a6fff1136dc1d70fcce17ef362da35292d,0000000000000000000000000000000000000000..292dbd7ad6b480babd426aae3dadc51060b419ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,246 -1,0 +1,246 @@@
-     /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
 +//! Read configurations files.
 +
 +#![deny(clippy::missing_docs_in_private_items)]
 +
 +use lazy_static::lazy_static;
 +use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
 +use rustc_span::source_map;
 +use source_map::Span;
 +use std::path::{Path, PathBuf};
 +use std::sync::Mutex;
 +use std::{env, fmt, fs, io};
 +
 +/// Gets the configuration file from arguments.
 +pub fn file_from_args(args: &[NestedMetaItem]) -> Result<Option<PathBuf>, (&'static str, Span)> {
 +    for arg in args.iter().filter_map(NestedMetaItem::meta_item) {
 +        if arg.has_name(sym!(conf_file)) {
 +            return match arg.kind {
 +                MetaItemKind::Word | MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)),
 +                MetaItemKind::NameValue(ref value) => {
 +                    if let LitKind::Str(ref file, _) = value.kind {
 +                        Ok(Some(file.to_string().into()))
 +                    } else {
 +                        Err(("`conf_file` value must be a string", value.span))
 +                    }
 +                },
 +            };
 +        }
 +    }
 +
 +    Ok(None)
 +}
 +
 +/// Error from reading a configuration file.
 +#[derive(Debug)]
 +pub enum Error {
 +    /// An I/O error.
 +    Io(io::Error),
 +    /// Not valid toml or doesn't fit the expected config format
 +    Toml(String),
 +}
 +
 +impl fmt::Display for Error {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            Self::Io(err) => err.fmt(f),
 +            Self::Toml(err) => err.fmt(f),
 +        }
 +    }
 +}
 +
 +impl From<io::Error> for Error {
 +    fn from(e: io::Error) -> Self {
 +        Self::Io(e)
 +    }
 +}
 +
 +lazy_static! {
 +    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
 +}
 +
 +macro_rules! define_Conf {
 +    ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
 +        mod helpers {
 +            use serde::Deserialize;
 +            /// Type used to store lint configuration.
 +            #[derive(Deserialize)]
 +            #[serde(rename_all = "kebab-case", deny_unknown_fields)]
 +            pub struct Conf {
 +                $(
 +                    #[$doc]
 +                    #[serde(default = $config_str)]
 +                    #[serde(with = $config_str)]
 +                    pub $config: $Ty,
 +                )+
 +                #[allow(dead_code)]
 +                #[serde(default)]
 +                third_party: Option<::toml::Value>,
 +            }
 +
 +            $(
 +                mod $config {
 +                    use serde::Deserialize;
 +                    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
 +                        use super::super::{ERRORS, Error};
 +                        Ok(
 +                            <$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
 +                                ERRORS
 +                                    .lock()
 +                                    .expect("no threading here")
 +                                    .push(Error::Toml(e.to_string()));
 +                                super::$config()
 +                            })
 +                        )
 +                    }
 +                }
 +
 +                #[must_use]
 +                fn $config() -> $Ty {
 +                    let x = $default;
 +                    x
 +                }
 +            )+
 +        }
 +    };
 +}
 +
 +pub use self::helpers::Conf;
 +define_Conf! {
 +    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
 +    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
 +    /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
 +    (cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
 +    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
 +    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold": Option<u64>, None),
 +    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
 +    (doc_valid_idents, "doc_valid_idents": Vec<String>, [
 +        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
 +        "DirectX",
 +        "ECMAScript",
 +        "GPLv2", "GPLv3",
 +        "GitHub", "GitLab",
 +        "IPv4", "IPv6",
 +        "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
 +        "NaN", "NaNs",
 +        "OAuth",
 +        "OCaml",
 +        "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
 +        "TensorFlow",
 +        "TrueType",
 +        "iOS", "macOS",
 +        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
 +        "MinGW",
 +        "CamelCase",
 +    ].iter().map(ToString::to_string).collect()),
 +    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
 +    (too_many_arguments_threshold, "too_many_arguments_threshold": u64, 7),
 +    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
 +    (type_complexity_threshold, "type_complexity_threshold": u64, 250),
 +    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
 +    (single_char_binding_names_threshold, "single_char_binding_names_threshold": u64, 4),
++    /// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
 +    (too_large_for_stack, "too_large_for_stack": u64, 200),
 +    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
 +    (enum_variant_name_threshold, "enum_variant_name_threshold": u64, 3),
 +    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
 +    (enum_variant_size_threshold, "enum_variant_size_threshold": u64, 200),
 +    /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
 +    (verbose_bit_mask_threshold, "verbose_bit_mask_threshold": u64, 1),
 +    /// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
 +    (literal_representation_threshold, "literal_representation_threshold": u64, 16384),
 +    /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
 +    (trivial_copy_size_limit, "trivial_copy_size_limit": Option<u64>, None),
 +    /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
 +    (too_many_lines_threshold, "too_many_lines_threshold": u64, 100),
 +    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. The maximum allowed size for arrays on the stack
 +    (array_size_threshold, "array_size_threshold": u64, 512_000),
 +    /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
 +    (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096),
 +    /// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
 +    (max_trait_bounds, "max_trait_bounds": u64, 3),
 +    /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have
 +    (max_struct_bools, "max_struct_bools": u64, 3),
 +    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
 +    (max_fn_params_bools, "max_fn_params_bools": u64, 3),
 +    /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
 +    (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
 +}
 +
 +impl Default for Conf {
 +    #[must_use]
 +    fn default() -> Self {
 +        toml::from_str("").expect("we never error on empty config files")
 +    }
 +}
 +
 +/// Search for the configuration file.
 +pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
 +    /// Possible filename to search for.
 +    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
 +
 +    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
 +    // If neither of those exist, use ".".
 +    let mut current = env::var_os("CLIPPY_CONF_DIR")
 +        .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
 +        .map_or_else(|| PathBuf::from("."), PathBuf::from);
 +    loop {
 +        for config_file_name in &CONFIG_FILE_NAMES {
 +            let config_file = current.join(config_file_name);
 +            match fs::metadata(&config_file) {
 +                // Only return if it's a file to handle the unlikely situation of a directory named
 +                // `clippy.toml`.
 +                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
 +                // Return the error if it's something other than `NotFound`; otherwise we didn't
 +                // find the project file yet, and continue searching.
 +                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
 +                _ => {},
 +            }
 +        }
 +
 +        // If the current directory has no parent, we're done searching.
 +        if !current.pop() {
 +            return Ok(None);
 +        }
 +    }
 +}
 +
 +/// Produces a `Conf` filled with the default values and forwards the errors
 +///
 +/// Used internally for convenience
 +fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
 +    (Conf::default(), errors)
 +}
 +
 +/// Read the `toml` configuration file.
 +///
 +/// In case of error, the function tries to continue as much as possible.
 +pub fn read(path: &Path) -> (Conf, Vec<Error>) {
 +    let content = match fs::read_to_string(path) {
 +        Ok(content) => content,
 +        Err(err) => return default(vec![err.into()]),
 +    };
 +
 +    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
 +    match toml::from_str(&content) {
 +        Ok(toml) => {
 +            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
 +
 +            let toml_ref: &Conf = &toml;
 +
 +            let cyc_field: Option<u64> = toml_ref.cyclomatic_complexity_threshold;
 +
 +            if cyc_field.is_some() {
 +                let cyc_err = "found deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.".to_string();
 +                errors.push(Error::Toml(cyc_err));
 +            }
 +
 +            (toml, errors)
 +        },
 +        Err(e) => {
 +            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
 +            errors.push(Error::Toml(e.to_string()));
 +
 +            default(errors)
 +        },
 +    }
 +}
index ba15456014d35e730a7876b0077600ec59d13867,0000000000000000000000000000000000000000..8563b469a30dd73772ee71722bdf04520f67575d
mode 100644,000000..100644
--- /dev/null
@@@ -1,241 -1,0 +1,243 @@@
-         hir::ExprKind::Call(ref path, ref args) if matches!(
-             path.kind,
-             hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
-         ) => Some(Range {
-             start: Some(&args[0]),
-             end: Some(&args[1]),
-             limits: ast::RangeLimits::Closed,
-         }),
-         hir::ExprKind::Struct(ref path, ref fields, None) => {
-             match path {
-                 hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
-                     start: None,
-                     end: None,
-                     limits: ast::RangeLimits::HalfOpen,
-                 }),
-                 hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
-                     start: Some(get_field("start", fields)?),
-                     end: None,
-                     limits: ast::RangeLimits::HalfOpen,
-                 }),
-                 hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
-                     start: Some(get_field("start", fields)?),
-                     end: Some(get_field("end", fields)?),
-                     limits: ast::RangeLimits::HalfOpen,
-                 }),
-                 hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
-                     start: None,
-                     end: Some(get_field("end", fields)?),
-                     limits: ast::RangeLimits::Closed,
-                 }),
-                 hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
-                     start: None,
-                     end: Some(get_field("end", fields)?),
-                     limits: ast::RangeLimits::HalfOpen,
-                 }),
-                 _ => None,
-             }
 +//! This module contains functions for retrieve the original AST from lowered
 +//! `hir`.
 +
 +#![deny(clippy::missing_docs_in_private_items)]
 +
 +use crate::utils::{is_expn_of, match_def_path, paths};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +
 +/// Converts a hir binary operator to the corresponding `ast` type.
 +#[must_use]
 +pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
 +    match op {
 +        hir::BinOpKind::Eq => ast::BinOpKind::Eq,
 +        hir::BinOpKind::Ge => ast::BinOpKind::Ge,
 +        hir::BinOpKind::Gt => ast::BinOpKind::Gt,
 +        hir::BinOpKind::Le => ast::BinOpKind::Le,
 +        hir::BinOpKind::Lt => ast::BinOpKind::Lt,
 +        hir::BinOpKind::Ne => ast::BinOpKind::Ne,
 +        hir::BinOpKind::Or => ast::BinOpKind::Or,
 +        hir::BinOpKind::Add => ast::BinOpKind::Add,
 +        hir::BinOpKind::And => ast::BinOpKind::And,
 +        hir::BinOpKind::BitAnd => ast::BinOpKind::BitAnd,
 +        hir::BinOpKind::BitOr => ast::BinOpKind::BitOr,
 +        hir::BinOpKind::BitXor => ast::BinOpKind::BitXor,
 +        hir::BinOpKind::Div => ast::BinOpKind::Div,
 +        hir::BinOpKind::Mul => ast::BinOpKind::Mul,
 +        hir::BinOpKind::Rem => ast::BinOpKind::Rem,
 +        hir::BinOpKind::Shl => ast::BinOpKind::Shl,
 +        hir::BinOpKind::Shr => ast::BinOpKind::Shr,
 +        hir::BinOpKind::Sub => ast::BinOpKind::Sub,
 +    }
 +}
 +
 +/// Represent a range akin to `ast::ExprKind::Range`.
 +#[derive(Debug, Copy, Clone)]
 +pub struct Range<'a> {
 +    /// The lower bound of the range, or `None` for ranges such as `..X`.
 +    pub start: Option<&'a hir::Expr<'a>>,
 +    /// The upper bound of the range, or `None` for ranges such as `X..`.
 +    pub end: Option<&'a hir::Expr<'a>>,
 +    /// Whether the interval is open or closed.
 +    pub limits: ast::RangeLimits,
 +}
 +
 +/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
 +pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
 +    /// Finds the field named `name` in the field. Always return `Some` for
 +    /// convenience.
 +    fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Expr<'c>> {
 +        let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr;
 +
 +        Some(expr)
 +    }
 +
 +    match expr.kind {
++        hir::ExprKind::Call(ref path, ref args)
++            if matches!(
++                path.kind,
++                hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
++            ) =>
++        {
++            Some(Range {
++                start: Some(&args[0]),
++                end: Some(&args[1]),
++                limits: ast::RangeLimits::Closed,
++            })
++        },
++        hir::ExprKind::Struct(ref path, ref fields, None) => match path {
++            hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
++                start: None,
++                end: None,
++                limits: ast::RangeLimits::HalfOpen,
++            }),
++            hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
++                start: Some(get_field("start", fields)?),
++                end: None,
++                limits: ast::RangeLimits::HalfOpen,
++            }),
++            hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
++                start: Some(get_field("start", fields)?),
++                end: Some(get_field("end", fields)?),
++                limits: ast::RangeLimits::HalfOpen,
++            }),
++            hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
++                start: None,
++                end: Some(get_field("end", fields)?),
++                limits: ast::RangeLimits::Closed,
++            }),
++            hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
++                start: None,
++                end: Some(get_field("end", fields)?),
++                limits: ast::RangeLimits::HalfOpen,
++            }),
++            _ => None,
 +        },
 +        _ => None,
 +    }
 +}
 +
 +/// Checks if a `let` statement is from a `for` loop desugaring.
 +pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
 +    // This will detect plain for-loops without an actual variable binding:
 +    //
 +    // ```
 +    // for x in some_vec {
 +    //     // do stuff
 +    // }
 +    // ```
 +    if_chain! {
 +        if let Some(ref expr) = local.init;
 +        if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
 +        then {
 +            return true;
 +        }
 +    }
 +
 +    // This detects a variable binding in for loop to avoid `let_unit_value`
 +    // lint (see issue #1964).
 +    //
 +    // ```
 +    // for _ in vec![()] {
 +    //     // anything
 +    // }
 +    // ```
 +    if let hir::LocalSource::ForLoopDesugar = local.source {
 +        return true;
 +    }
 +
 +    false
 +}
 +
 +/// Recover the essential nodes of a desugared for loop:
 +/// `for pat in arg { body }` becomes `(pat, arg, body)`.
 +pub fn for_loop<'tcx>(
 +    expr: &'tcx hir::Expr<'tcx>,
 +) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
 +    if_chain! {
 +        if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
 +        if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
 +        if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
 +        if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.kind;
 +        if block.expr.is_none();
 +        if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
 +        if let hir::StmtKind::Local(ref local) = let_stmt.kind;
 +        if let hir::StmtKind::Expr(ref expr) = body.kind;
 +        then {
 +            return Some((&*local.pat, &iterargs[0], expr));
 +        }
 +    }
 +    None
 +}
 +
 +/// Recover the essential nodes of a desugared while loop:
 +/// `while cond { body }` becomes `(cond, body)`.
 +pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
 +    if_chain! {
 +        if let hir::ExprKind::Loop(block, _, hir::LoopSource::While) = &expr.kind;
 +        if let hir::Block { expr: Some(expr), .. } = &**block;
 +        if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
 +        if let hir::ExprKind::DropTemps(cond) = &cond.kind;
 +        if let [arm, ..] = &arms[..];
 +        if let hir::Arm { body, .. } = arm;
 +        then {
 +            return Some((cond, body));
 +        }
 +    }
 +    None
 +}
 +
 +/// Recover the essential nodes of a desugared if block
 +/// `if cond { then } else { els }` becomes `(cond, then, Some(els))`
 +pub fn if_block<'tcx>(
 +    expr: &'tcx hir::Expr<'tcx>,
 +) -> Option<(
 +    &'tcx hir::Expr<'tcx>,
 +    &'tcx hir::Expr<'tcx>,
 +    Option<&'tcx hir::Expr<'tcx>>,
 +)> {
 +    if let hir::ExprKind::Match(ref cond, ref arms, hir::MatchSource::IfDesugar { contains_else_clause }) = expr.kind {
 +        let cond = if let hir::ExprKind::DropTemps(ref cond) = cond.kind {
 +            cond
 +        } else {
 +            panic!("If block desugar must contain DropTemps");
 +        };
 +        let then = &arms[0].body;
 +        let els = if contains_else_clause {
 +            Some(&*arms[1].body)
 +        } else {
 +            None
 +        };
 +        Some((cond, then, els))
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Represent the pre-expansion arguments of a `vec!` invocation.
 +pub enum VecArgs<'a> {
 +    /// `vec![elem; len]`
 +    Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>),
 +    /// `vec![a, b, c]`
 +    Vec(&'a [hir::Expr<'a>]),
 +}
 +
 +/// Returns the arguments of the `vec!` macro if this expression was expanded
 +/// from `vec!`.
 +pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
 +    if_chain! {
 +        if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
 +        if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +        if is_expn_of(fun.span, "vec").is_some();
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        then {
 +            return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
 +                // `vec![elem; size]` case
 +                Some(VecArgs::Repeat(&args[0], &args[1]))
 +            }
 +            else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
 +                // `vec![a, b, c]` case
 +                if_chain! {
 +                    if let hir::ExprKind::Box(ref boxed) = args[0].kind;
 +                    if let hir::ExprKind::Array(ref args) = boxed.kind;
 +                    then {
 +                        return Some(VecArgs::Vec(&*args));
 +                    }
 +                }
 +
 +                None
 +            }
 +            else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
 +                Some(VecArgs::Vec(&[]))
 +            }
 +            else {
 +                None
 +            };
 +        }
 +    }
 +
 +    None
 +}
index 2eefd4a38a67a5056981c2622deaebedc78cc348,0000000000000000000000000000000000000000..c7263f48965a5a505e0e1f879fda4eaf2d0c5522
mode 100644,000000..100644
--- /dev/null
@@@ -1,761 -1,0 +1,762 @@@
-     BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat,
-     FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName,
-     Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 +use crate::consts::{constant_context, constant_simple};
 +use crate::utils::differing_macro_contexts;
 +use rustc_ast::ast::InlineAsmTemplatePiece;
 +use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 +use rustc_hir::{
-     /// If is true, never consider as equal expressions containing function
-     /// calls.
-     ignore_fn: bool,
++    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, FnRetTy,
++    GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path,
++    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 +};
 +use rustc_lint::LateContext;
 +use rustc_middle::ich::StableHashingContextProvider;
 +use rustc_middle::ty::TypeckResults;
 +use rustc_span::Symbol;
 +use std::hash::Hash;
 +
 +/// Type used to check whether two ast are the same. This is different from the
 +/// operator
 +/// `==` on ast types as this operator would compare true equality with ID and
 +/// span.
 +///
 +/// Note that some expressions kinds are not considered but could be added.
 +pub struct SpanlessEq<'a, 'tcx> {
 +    /// Context used to evaluate constant expressions.
 +    cx: &'a LateContext<'tcx>,
 +    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-             ignore_fn: false,
++    allow_side_effects: bool,
 +}
 +
 +impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
 +    pub fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            maybe_typeck_results: cx.maybe_typeck_results(),
-     pub fn ignore_fn(self) -> Self {
++            allow_side_effects: true,
 +        }
 +    }
 +
-             ignore_fn: true,
++    /// Consider expressions containing potential side effects as not equal.
++    pub fn deny_side_effects(self) -> Self {
 +        Self {
-         if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
++            allow_side_effects: false,
 +            ..self
 +        }
 +    }
 +
 +    /// Checks whether two statements are the same.
 +    pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
 +        match (&left.kind, &right.kind) {
 +            (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
 +                self.eq_pat(&l.pat, &r.pat)
 +                    && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
 +                    && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
 +            },
 +            (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
 +                self.eq_expr(l, r)
 +            },
 +            _ => false,
 +        }
 +    }
 +
 +    /// Checks whether two blocks are the same.
 +    pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
 +        over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
 +            && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-                 self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
++        if !self.allow_side_effects && differing_macro_contexts(left.span, right.span) {
 +            return false;
 +        }
 +
 +        if let Some(typeck_results) = self.maybe_typeck_results {
 +            if let (Some(l), Some(r)) = (
 +                constant_simple(self.cx, typeck_results, left),
 +                constant_simple(self.cx, typeck_results, right),
 +            ) {
 +                if l == r {
 +                    return true;
 +                }
 +            }
 +        }
 +
 +        match (&left.kind, &right.kind) {
 +            (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
 +                lb == rb && l_mut == r_mut && self.eq_expr(le, re)
 +            },
 +            (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
 +                both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
 +            },
 +            (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
-                 lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
++                self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
 +            },
 +            (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
-                 !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
++                self.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
 +            },
 +            (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
 +            (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
 +                l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
 +                    || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
 +                        l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
 +                    })
 +            },
 +            (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
 +                both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
 +                    && both(le, re, |l, r| self.eq_expr(l, r))
 +            },
 +            (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
 +            (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
-                 !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
++                self.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
 +            },
 +            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
 +            | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
 +                self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
 +            },
 +            (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
 +                l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
 +            },
 +            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
 +                self.eq_expr(la, ra) && self.eq_expr(li, ri)
 +            },
 +            (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
 +            (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
 +                lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str())
 +            },
 +            (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
 +                ls == rs
 +                    && self.eq_expr(le, re)
 +                    && over(la, ra, |l, r| {
 +                        self.eq_expr(&l.body, &r.body)
 +                            && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
 +                            && self.eq_pat(&l.pat, &r.pat)
 +                    })
 +            },
 +            (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
-         match (&left, &right) {
-             (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) =>
-                 li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp),
-         }
++                self.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
 +            },
 +            (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
 +                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
 +                let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
 +                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
 +                let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 +
 +                self.eq_expr(le, re) && ll == rl
 +            },
 +            (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
 +            (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
 +            (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
 +                self.eq_qpath(l_path, r_path)
 +                    && both(lo, ro, |l, r| self.eq_expr(l, r))
 +                    && over(lf, rf, |l, r| self.eq_field(l, r))
 +            },
 +            (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
 +            (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
 +            (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
 +            (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
 +            _ => false,
 +        }
 +    }
 +
 +    fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
 +        over(left, right, |l, r| self.eq_expr(l, r))
 +    }
 +
 +    fn eq_field(&mut self, left: &Field<'_>, right: &Field<'_>) -> bool {
 +        left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
 +    }
 +
 +    fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
 +        match (left, right) {
 +            (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
 +        }
 +    }
 +
 +    fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
 +        match (left, right) {
 +            (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
 +            (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
 +            _ => false,
 +        }
 +    }
 +
 +    fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool {
 +        left.name == right.name
 +    }
 +
 +    pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
-             (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) =>
-                 llang_item == rlang_item,
++        let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right);
++        li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp)
 +    }
 +
 +    /// Checks whether two patterns are the same.
 +    pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
 +        match (&left.kind, &right.kind) {
 +            (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
 +            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
 +                self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_fieldpat(l, r))
 +            },
 +            (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
 +                self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
 +            },
 +            (&PatKind::Binding(ref lb, .., ref li, ref lp), &PatKind::Binding(ref rb, .., ref ri, ref rp)) => {
 +                lb == rb && li.name.as_str() == ri.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
 +            },
 +            (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
 +            (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
 +            (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
 +                ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
 +            },
 +            (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
 +                both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
 +            },
 +            (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
 +            (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
 +                over(ls, rs, |l, r| self.eq_pat(l, r))
 +                    && over(le, re, |l, r| self.eq_pat(l, r))
 +                    && both(li, ri, |l, r| self.eq_pat(l, r))
 +            },
 +            (&PatKind::Wild, &PatKind::Wild) => true,
 +            _ => false,
 +        }
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
 +        match (left, right) {
 +            (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
 +                both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
 +            },
 +            (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
 +                self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
 +            },
-             }
++            (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
 +            _ => false,
 +        }
 +    }
 +
 +    fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
 +        left.is_global() == right.is_global()
 +            && over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
 +    }
 +
 +    fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
 +        if !(left.parenthesized || right.parenthesized) {
 +            over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
 +                && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
 +        } else if left.parenthesized && right.parenthesized {
 +            over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
 +                && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
 +                    self.eq_ty(l, r)
 +                })
 +        } else {
 +            false
 +        }
 +    }
 +
 +    pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
 +        left.len() == right.len() && left.iter().zip(right).all(|(l, r)| self.eq_path_segment(l, r))
 +    }
 +
 +    pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
 +        // The == of idents doesn't work with different contexts,
 +        // we have to be explicit about hygiene
 +        if left.ident.as_str() != right.ident.as_str() {
 +            return false;
 +        }
 +        match (&left.args, &right.args) {
 +            (&None, &None) => true,
 +            (&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r),
 +            _ => false,
 +        }
 +    }
 +
 +    pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
 +        self.eq_ty_kind(&left.kind, &right.kind)
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool {
 +        match (left, right) {
 +            (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
 +            (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
 +                let old_maybe_typeck_results = self.maybe_typeck_results;
 +
 +                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
 +                self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(ll_id.body));
 +                let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
 +
 +                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
 +                self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(rl_id.body));
 +                let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 +
 +                let eq_ty = self.eq_ty(lt, rt);
 +                self.maybe_typeck_results = old_maybe_typeck_results;
 +                eq_ty && ll == rl
 +            },
 +            (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
 +                l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
 +            },
 +            (&TyKind::Rptr(_, ref l_rmut), &TyKind::Rptr(_, ref r_rmut)) => {
 +                l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
 +            },
 +            (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
 +            (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
 +            (&TyKind::Infer, &TyKind::Infer) => true,
 +            _ => false,
 +        }
 +    }
 +
 +    fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
 +        left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
 +    }
 +}
 +
 +fn swap_binop<'a>(
 +    binop: BinOpKind,
 +    lhs: &'a Expr<'a>,
 +    rhs: &'a Expr<'a>,
 +) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> {
 +    match binop {
 +        BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => {
 +            Some((binop, rhs, lhs))
 +        },
 +        BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
 +        BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
 +        BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
 +        BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
 +        BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698
 +        | BinOpKind::Shl
 +        | BinOpKind::Shr
 +        | BinOpKind::Rem
 +        | BinOpKind::Sub
 +        | BinOpKind::Div
 +        | BinOpKind::And
 +        | BinOpKind::Or => None,
 +    }
 +}
 +
 +/// Checks if the two `Option`s are both `None` or some equal values as per
 +/// `eq_fn`.
 +pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
 +    l.as_ref()
 +        .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
 +}
 +
 +/// Checks if two slices are equal as per `eq_fn`.
 +pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
 +    left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 +}
 +
++/// Checks if two expressions evaluate to the same value, and don't contain any side effects.
++pub fn eq_expr_value(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>) -> bool {
++    SpanlessEq::new(cx).deny_side_effects().eq_expr(left, right)
++}
++
 +/// Type used to hash an ast element. This is different from the `Hash` trait
 +/// on ast types as this
 +/// trait would consider IDs and spans.
 +///
 +/// All expressions kind are hashed, but some might have a weaker hash.
 +pub struct SpanlessHash<'a, 'tcx> {
 +    /// Context used to evaluate constant expressions.
 +    cx: &'a LateContext<'tcx>,
 +    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
 +    s: StableHasher,
 +}
 +
 +impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 +    pub fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            maybe_typeck_results: cx.maybe_typeck_results(),
 +            s: StableHasher::new(),
 +        }
 +    }
 +
 +    pub fn finish(self) -> u64 {
 +        self.s.finish()
 +    }
 +
 +    pub fn hash_block(&mut self, b: &Block<'_>) {
 +        for s in b.stmts {
 +            self.hash_stmt(s);
 +        }
 +
 +        if let Some(ref e) = b.expr {
 +            self.hash_expr(e);
 +        }
 +
 +        match b.rules {
 +            BlockCheckMode::DefaultBlock => 0,
 +            BlockCheckMode::UnsafeBlock(_) => 1,
 +            BlockCheckMode::PushUnsafeBlock(_) => 2,
 +            BlockCheckMode::PopUnsafeBlock(_) => 3,
 +        }
 +        .hash(&mut self.s);
 +    }
 +
 +    #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
 +    pub fn hash_expr(&mut self, e: &Expr<'_>) {
 +        let simple_const = self
 +            .maybe_typeck_results
 +            .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
 +
 +        // const hashing may result in the same hash as some unrelated node, so add a sort of
 +        // discriminant depending on which path we're choosing next
 +        simple_const.is_some().hash(&mut self.s);
 +
 +        if let Some(e) = simple_const {
 +            return e.hash(&mut self.s);
 +        }
 +
 +        std::mem::discriminant(&e.kind).hash(&mut self.s);
 +
 +        match e.kind {
 +            ExprKind::AddrOf(kind, m, ref e) => {
 +                match kind {
 +                    BorrowKind::Ref => 0,
 +                    BorrowKind::Raw => 1,
 +                }
 +                .hash(&mut self.s);
 +                m.hash(&mut self.s);
 +                self.hash_expr(e);
 +            },
 +            ExprKind::Continue(i) => {
 +                if let Some(i) = i.label {
 +                    self.hash_name(i.ident.name);
 +                }
 +            },
 +            ExprKind::Assign(ref l, ref r, _) => {
 +                self.hash_expr(l);
 +                self.hash_expr(r);
 +            },
 +            ExprKind::AssignOp(ref o, ref l, ref r) => {
 +                o.node
 +                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
 +                self.hash_expr(l);
 +                self.hash_expr(r);
 +            },
 +            ExprKind::Block(ref b, _) => {
 +                self.hash_block(b);
 +            },
 +            ExprKind::Binary(op, ref l, ref r) => {
 +                op.node
 +                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
 +                self.hash_expr(l);
 +                self.hash_expr(r);
 +            },
 +            ExprKind::Break(i, ref j) => {
 +                if let Some(i) = i.label {
 +                    self.hash_name(i.ident.name);
 +                }
 +                if let Some(ref j) = *j {
 +                    self.hash_expr(&*j);
 +                }
 +            },
 +            ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
 +                self.hash_expr(e);
 +            },
 +            ExprKind::Call(ref fun, args) => {
 +                self.hash_expr(fun);
 +                self.hash_exprs(args);
 +            },
 +            ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
 +                self.hash_expr(e);
 +                self.hash_ty(ty);
 +            },
 +            ExprKind::Closure(cap, _, eid, _, _) => {
 +                match cap {
 +                    CaptureBy::Value => 0,
 +                    CaptureBy::Ref => 1,
 +                }
 +                .hash(&mut self.s);
 +                // closures inherit TypeckResults
 +                self.hash_expr(&self.cx.tcx.hir().body(eid).value);
 +            },
 +            ExprKind::Field(ref e, ref f) => {
 +                self.hash_expr(e);
 +                self.hash_name(f.name);
 +            },
 +            ExprKind::Index(ref a, ref i) => {
 +                self.hash_expr(a);
 +                self.hash_expr(i);
 +            },
 +            ExprKind::InlineAsm(ref asm) => {
 +                for piece in asm.template {
 +                    match piece {
 +                        InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
 +                        InlineAsmTemplatePiece::Placeholder {
 +                            operand_idx,
 +                            modifier,
 +                            span: _,
 +                        } => {
 +                            operand_idx.hash(&mut self.s);
 +                            modifier.hash(&mut self.s);
 +                        },
 +                    }
 +                }
 +                asm.options.hash(&mut self.s);
 +                for op in asm.operands {
 +                    match op {
 +                        InlineAsmOperand::In { reg, expr } => {
 +                            reg.hash(&mut self.s);
 +                            self.hash_expr(expr);
 +                        },
 +                        InlineAsmOperand::Out { reg, late, expr } => {
 +                            reg.hash(&mut self.s);
 +                            late.hash(&mut self.s);
 +                            if let Some(expr) = expr {
 +                                self.hash_expr(expr);
 +                            }
 +                        },
 +                        InlineAsmOperand::InOut { reg, late, expr } => {
 +                            reg.hash(&mut self.s);
 +                            late.hash(&mut self.s);
 +                            self.hash_expr(expr);
 +                        },
 +                        InlineAsmOperand::SplitInOut {
 +                            reg,
 +                            late,
 +                            in_expr,
 +                            out_expr,
 +                        } => {
 +                            reg.hash(&mut self.s);
 +                            late.hash(&mut self.s);
 +                            self.hash_expr(in_expr);
 +                            if let Some(out_expr) = out_expr {
 +                                self.hash_expr(out_expr);
 +                            }
 +                        },
 +                        InlineAsmOperand::Const { expr } | InlineAsmOperand::Sym { expr } => self.hash_expr(expr),
 +                    }
 +                }
 +            },
 +            ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
 +            ExprKind::Lit(ref l) => {
 +                l.node.hash(&mut self.s);
 +            },
 +            ExprKind::Loop(ref b, ref i, _) => {
 +                self.hash_block(b);
 +                if let Some(i) = *i {
 +                    self.hash_name(i.ident.name);
 +                }
 +            },
 +            ExprKind::Match(ref e, arms, ref s) => {
 +                self.hash_expr(e);
 +
 +                for arm in arms {
 +                    // TODO: arm.pat?
 +                    if let Some(ref e) = arm.guard {
 +                        self.hash_guard(e);
 +                    }
 +                    self.hash_expr(&arm.body);
 +                }
 +
 +                s.hash(&mut self.s);
 +            },
 +            ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
 +                self.hash_name(path.ident.name);
 +                self.hash_exprs(args);
 +            },
 +            ExprKind::Repeat(ref e, ref l_id) => {
 +                self.hash_expr(e);
 +                self.hash_body(l_id.body);
 +            },
 +            ExprKind::Ret(ref e) => {
 +                if let Some(ref e) = *e {
 +                    self.hash_expr(e);
 +                }
 +            },
 +            ExprKind::Path(ref qpath) => {
 +                self.hash_qpath(qpath);
 +            },
 +            ExprKind::Struct(ref path, fields, ref expr) => {
 +                self.hash_qpath(path);
 +
 +                for f in fields {
 +                    self.hash_name(f.ident.name);
 +                    self.hash_expr(&f.expr);
 +                }
 +
 +                if let Some(ref e) = *expr {
 +                    self.hash_expr(e);
 +                }
 +            },
 +            ExprKind::Tup(tup) => {
 +                self.hash_exprs(tup);
 +            },
 +            ExprKind::Array(v) => {
 +                self.hash_exprs(v);
 +            },
 +            ExprKind::Unary(lop, ref le) => {
 +                lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
 +                self.hash_expr(le);
 +            },
 +        }
 +    }
 +
 +    pub fn hash_exprs(&mut self, e: &[Expr<'_>]) {
 +        for e in e {
 +            self.hash_expr(e);
 +        }
 +    }
 +
 +    pub fn hash_name(&mut self, n: Symbol) {
 +        n.as_str().hash(&mut self.s);
 +    }
 +
 +    pub fn hash_qpath(&mut self, p: &QPath<'_>) {
 +        match *p {
 +            QPath::Resolved(_, ref path) => {
 +                self.hash_path(path);
 +            },
 +            QPath::TypeRelative(_, ref path) => {
 +                self.hash_name(path.ident.name);
 +            },
 +            QPath::LangItem(lang_item, ..) => {
 +                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
-                 }
++            },
 +        }
 +        // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
 +    }
 +
 +    pub fn hash_path(&mut self, p: &Path<'_>) {
 +        p.is_global().hash(&mut self.s);
 +        for p in p.segments {
 +            self.hash_name(p.ident.name);
 +        }
 +    }
 +
 +    pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
 +        std::mem::discriminant(&b.kind).hash(&mut self.s);
 +
 +        match &b.kind {
 +            StmtKind::Local(local) => {
 +                if let Some(ref init) = local.init {
 +                    self.hash_expr(init);
 +                }
 +            },
 +            StmtKind::Item(..) => {},
 +            StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
 +                self.hash_expr(expr);
 +            },
 +        }
 +    }
 +
 +    pub fn hash_guard(&mut self, g: &Guard<'_>) {
 +        match g {
 +            Guard::If(ref expr) => {
 +                self.hash_expr(expr);
 +            },
 +        }
 +    }
 +
 +    pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
 +        std::mem::discriminant(&lifetime.name).hash(&mut self.s);
 +        if let LifetimeName::Param(ref name) = lifetime.name {
 +            std::mem::discriminant(name).hash(&mut self.s);
 +            match name {
 +                ParamName::Plain(ref ident) => {
 +                    ident.name.hash(&mut self.s);
 +                },
 +                ParamName::Fresh(ref size) => {
 +                    size.hash(&mut self.s);
 +                },
 +                ParamName::Error => {},
 +            }
 +        }
 +    }
 +
 +    pub fn hash_ty(&mut self, ty: &Ty<'_>) {
 +        self.hash_tykind(&ty.kind);
 +    }
 +
 +    pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
 +        std::mem::discriminant(ty).hash(&mut self.s);
 +        match ty {
 +            TyKind::Slice(ty) => {
 +                self.hash_ty(ty);
 +            },
 +            TyKind::Array(ty, anon_const) => {
 +                self.hash_ty(ty);
 +                self.hash_body(anon_const.body);
 +            },
 +            TyKind::Ptr(mut_ty) => {
 +                self.hash_ty(&mut_ty.ty);
 +                mut_ty.mutbl.hash(&mut self.s);
 +            },
 +            TyKind::Rptr(lifetime, mut_ty) => {
 +                self.hash_lifetime(lifetime);
 +                self.hash_ty(&mut_ty.ty);
 +                mut_ty.mutbl.hash(&mut self.s);
 +            },
 +            TyKind::BareFn(bfn) => {
 +                bfn.unsafety.hash(&mut self.s);
 +                bfn.abi.hash(&mut self.s);
 +                for arg in bfn.decl.inputs {
 +                    self.hash_ty(&arg);
 +                }
 +                match bfn.decl.output {
 +                    FnRetTy::DefaultReturn(_) => {
 +                        ().hash(&mut self.s);
 +                    },
 +                    FnRetTy::Return(ref ty) => {
 +                        self.hash_ty(ty);
 +                    },
 +                }
 +                bfn.decl.c_variadic.hash(&mut self.s);
 +            },
 +            TyKind::Tup(ty_list) => {
 +                for ty in *ty_list {
 +                    self.hash_ty(ty);
 +                }
 +            },
 +            TyKind::Path(qpath) => match qpath {
 +                QPath::Resolved(ref maybe_ty, ref path) => {
 +                    if let Some(ref ty) = maybe_ty {
 +                        self.hash_ty(ty);
 +                    }
 +                    for segment in path.segments {
 +                        segment.ident.name.hash(&mut self.s);
 +                        self.hash_generic_args(segment.generic_args().args);
 +                    }
 +                },
 +                QPath::TypeRelative(ref ty, ref segment) => {
 +                    self.hash_ty(ty);
 +                    segment.ident.name.hash(&mut self.s);
 +                },
 +                QPath::LangItem(lang_item, ..) => {
 +                    lang_item.hash(&mut self.s);
++                },
 +            },
 +            TyKind::OpaqueDef(_, arg_list) => {
 +                self.hash_generic_args(arg_list);
 +            },
 +            TyKind::TraitObject(_, lifetime) => {
 +                self.hash_lifetime(lifetime);
 +            },
 +            TyKind::Typeof(anon_const) => {
 +                self.hash_body(anon_const.body);
 +            },
 +            TyKind::Err | TyKind::Infer | TyKind::Never => {},
 +        }
 +    }
 +
 +    pub fn hash_body(&mut self, body_id: BodyId) {
 +        // swap out TypeckResults when hashing a body
 +        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
 +        self.hash_expr(&self.cx.tcx.hir().body(body_id).value);
 +        self.maybe_typeck_results = old_maybe_typeck_results;
 +    }
 +
 +    fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
 +        for arg in arg_list {
 +            match arg {
 +                GenericArg::Lifetime(ref l) => self.hash_lifetime(l),
 +                GenericArg::Type(ref ty) => self.hash_ty(&ty),
 +                GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
 +            }
 +        }
 +    }
 +}
index 6c2356799142db6b609fb6c2a77be4c00f8266a2,0000000000000000000000000000000000000000..8fa5d22210a3691f585b16256dc54e5464827d85
mode 100644,000000..100644
--- /dev/null
@@@ -1,655 -1,0 +1,654 @@@
- use crate::utils::SpanlessEq;
 +use crate::utils::{
 +    is_expn_of, match_def_path, match_qpath, match_type, method_calls, paths, run_lints, snippet, span_lint,
-     span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty,
++    span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty, SpanlessEq,
 +};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, 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::hir_id::CRATE_HIR_ID;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, StmtKind, Ty, TyKind};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::symbol::{Symbol, SymbolStr};
 +
 +use std::borrow::{Borrow, Cow};
 +
 +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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// *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_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 +
 +impl EarlyLintPass for ClippyLintsInternal {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
 +        if let Some(utils) = krate
 +            .module
 +            .items
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == "utils")
 +        {
 +            if let ItemKind::Mod(ref utils_mod) = utils.kind {
 +                if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name.as_str() == "paths") {
 +                    if let ItemKind::Mod(ref paths_mod) = paths.kind {
 +                        let mut last_name: Option<SymbolStr> = None;
 +                        for item in &*paths_mod.items {
 +                            let name = item.ident.as_str();
 +                            if let Some(ref 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]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if !run_lints(cx, &[DEFAULT_LINT], item.hir_id) {
 +            return;
 +        }
 +
 +        if let hir::ItemKind::Static(ref ty, Mutability::Not, body_id) = item.kind {
 +            if is_lint_ref_type(cx, ty) {
 +                let expr = &cx.tcx.hir().body(body_id).value;
 +                if_chain! {
 +                    if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind;
 +                    if let ExprKind::Struct(_, ref 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 {
 +                of_trait: None,
 +                items: ref 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>, _: &'tcx Crate<'_>) {
 +        if !run_lints(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: ref 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
 +}
 +
 +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 !run_lints(cx, &[COMPILER_LINT_FUNCTIONS], expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
 +            let fn_name = path.ident;
 +            if let Some(sugg) = self.map.get(&*fn_name.as_str());
 +            let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
 +            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 !run_lints(cx, &[OUTER_EXPN_EXPN_DATA], expr.hir_id) {
 +            return;
 +        }
 +
 +        let (method_names, arg_lists, spans) = method_calls(expr, 2);
 +        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_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 = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg));
 +            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) {
 +        if is_trigger_fn(fn_kind) {
 +            panic!("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 !run_lints(cx, &[COLLAPSIBLE_SPAN_LINT_CALLS], expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(ref func, ref and_then_args) = expr.kind;
 +            if let ExprKind::Path(ref path) = func.kind;
 +            if match_qpath(path, &["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);
 +            if let ExprKind::Block(block, _) = &body.value.kind;
 +            let stmts = &block.stmts;
 +            if stmts.len() == 1 && block.expr.is_none();
 +            if let StmtKind::Semi(only_expr) = &stmts[0].kind;
 +            if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind;
 +            let and_then_snippets = get_and_then_snippets(cx, and_then_args);
-             let mut sle = SpanlessEq::new(cx).ignore_fn();
++            let mut sle = SpanlessEq::new(cx).deny_side_effects();
 +            then {
 +                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,
 +    );
 +}
index a56b8203513e6d2c8945a5b520cb9093d4483b40,0000000000000000000000000000000000000000..82005257115642072aa4c26858eeda9532904075
mode 100644,000000..100644
--- /dev/null
@@@ -1,1527 -1,0 +1,1555 @@@
- pub use self::hir_utils::{both, over, SpanlessEq, SpanlessHash};
 +#[macro_use]
 +pub mod sym;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
 +pub mod author;
 +pub mod camel_case;
 +pub mod comparisons;
 +pub mod conf;
 +pub mod constants;
 +mod diagnostics;
 +pub mod higher;
 +mod hir_utils;
 +pub mod inspector;
 +pub mod internal_lints;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod sugg;
 +pub mod usage;
 +pub use self::attrs::*;
 +pub use self::diagnostics::*;
- use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable};
++pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::borrow::Cow;
 +use std::mem;
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
 +use rustc_attr as attr;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::Node;
 +use rustc_hir::{
 +    def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind,
 +    MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety,
 +};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::map::Map;
- /// `snippet_with_applicabiliy`.
++use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
++use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
 +use rustc_mir::const_eval;
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::original_sp;
 +use rustc_span::symbol::{self, kw, Symbol};
 +use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 +use rustc_target::abi::Integer;
 +use rustc_trait_selection::traits::query::normalize::AtExt;
 +use smallvec::SmallVec;
 +
 +use crate::consts::{constant, Constant};
 +
 +/// 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()
 +}
 +
 +/// 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,
 +    }
 +}
 +
 +/// Returns `true` if this `span` was expanded by any macro.
 +#[must_use]
 +pub fn in_macro(span: Span) -> bool {
 +    if span.from_expansion() {
 +        !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
 +    } else {
 +        false
 +    }
 +}
 +// If the snippet is empty, it's an attribute that was inserted during macro
 +// expansion and we want to ignore those, because they could come from external
 +// sources that the user has no control over.
 +// For some reason these attributes don't have any expansion info on them, so
 +// we have to check it this way until there is a better way.
 +pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
 +    if let Some(snippet) = snippet_opt(cx, span) {
 +        if snippet.is_empty() {
 +            return false;
 +        }
 +    }
 +    true
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// Checks if type is struct, enum or union type with the given def path.
 +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 +    match ty.kind {
 +        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a diagnostic item
 +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind {
 +        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a lang item
 +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
 +    match ty.kind {
 +        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +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 an expression references a variable of the given name.
 +pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
 +    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
 +        if let [p] = path.segments {
 +            return p.ident.name == var;
 +        }
 +    }
 +    false
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, ref seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
 +    match *path {
 +        QPath::Resolved(_, ref path) => path.segments.get(0),
 +        QPath::TypeRelative(_, ref seg) => Some(seg),
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +/// 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(_, ref path) => match_path(path, segments),
 +        QPath::TypeRelative(ref ty, ref 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,
 +    }
 +}
 +
 +/// 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)
 +}
 +
 +/// Matches a `Path` against a slice of segment string literals, e.g.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_path_ast(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// Gets the definition associated to a path.
 +pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
 +    let crates = cx.tcx.crates();
 +    let krate = crates
 +        .iter()
 +        .find(|&&krate| cx.tcx.crate_name(krate).as_str() == path[0]);
 +    if let Some(krate) = krate {
 +        let krate = DefId {
 +            krate: *krate,
 +            index: CRATE_DEF_INDEX,
 +        };
 +        let mut items = cx.tcx.item_children(krate);
 +        let mut path_it = path.iter().skip(1).peekable();
 +
 +        loop {
 +            let segment = match path_it.next() {
 +                Some(segment) => segment,
 +                None => return None,
 +            };
 +
 +            let result = SmallVec::<[_; 8]>::new();
 +            for item in mem::replace(&mut items, cx.tcx.arena.alloc_slice(&result)).iter() {
 +                if item.ident.name.as_str() == *segment {
 +                    if path_it.peek().is_none() {
 +                        return Some(item.res);
 +                    }
 +
 +                    items = cx.tcx.item_children(item.res.def_id());
 +                    break;
 +                }
 +            }
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
 +    match qpath {
 +        hir::QPath::Resolved(_, path) => path.res,
 +        hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
 +            if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
 +                cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
 +            } else {
 +                Res::Err
 +            }
 +        },
 +    }
 +}
 +
 +/// 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> {
 +    let res = match path_to_res(cx, path) {
 +        Some(res) => res,
 +        None => return None,
 +    };
 +
 +    match res {
 +        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
 +        Res::Err => unreachable!("this trait resolution is impossible: {:?}", &path),
 +        _ => None,
 +    }
 +}
 +
 +/// Checks whether a type implements a trait.
 +/// See also `get_trait_def_id`.
 +pub fn implements_trait<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_id: DefId,
 +    ty_params: &[GenericArg<'tcx>],
 +) -> bool {
 +    // Do not check on infer_types to avoid panic in evaluate_obligation.
 +    if ty.has_infer_types() {
 +        return false;
 +    }
 +    let ty = cx.tcx.erase_regions(&ty);
 +    let ty_params = cx.tcx.mk_substs(ty_params.iter());
 +    cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
 +}
 +
 +/// 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{ of_trait: trait_ref, .. } = &item.kind;
 +        then { return trait_ref.as_ref(); }
 +    }
 +    None
 +}
 +
 +/// Checks whether this type implements `Drop`.
 +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.ty_adt_def() {
 +        Some(def) => def.has_dtor(cx.tcx),
 +        None => false,
 +    }
 +}
 +
 +/// Returns 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(ref path, _, ref 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(LOCAL_CRATE)
 +        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
 +}
 +
 +/// 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,
 +    }
 +}
 +
 +/// Gets the name of a `Pat`, if any.
 +pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
 +    match pat.kind {
 +        PatKind::Binding(.., ref spname, _) => Some(spname.name),
 +        PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
 +        PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
 +        _ => None,
 +    }
 +}
 +
 +struct ContainsName {
 +    name: Symbol,
 +    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
 +}
 +
 +/// Converts a span to a code snippet if available, otherwise use default.
 +///
 +/// This is useful if you want to provide suggestions for your lint or more generally, if you want
 +/// to convert a given `Span` to a `str`.
 +///
 +/// # Example
 +/// ```rust,ignore
 +/// snippet(cx, expr.span, "..")
 +/// ```
 +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
 +    snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
 +}
 +
 +/// Same as `snippet`, 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 snippet_with_applicability<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    applicability: &mut Applicability,
 +) -> Cow<'a, str> {
 +    if *applicability != Applicability::Unspecified && span.from_expansion() {
 +        *applicability = Applicability::MaybeIncorrect;
 +    }
 +    snippet_opt(cx, span).map_or_else(
 +        || {
 +            if *applicability == Applicability::MachineApplicable {
 +                *applicability = Applicability::HasPlaceholders;
 +            }
 +            Cow::Borrowed(default)
 +        },
 +        From::from,
 +    )
 +}
 +
 +/// Same as `snippet`, but should only be used when it's clear that the input span is
 +/// not a macro argument.
 +pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
 +    snippet(cx, span.source_callsite(), default)
 +}
 +
 +/// Converts a span to a code snippet. Returns `None` if not available.
 +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 +    cx.sess().source_map().span_to_snippet(span).ok()
 +}
 +
 +/// Converts a span (from a block) to a code snippet if available, otherwise use default.
 +///
 +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like
 +/// things which need to be printed as such.
 +///
 +/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the
 +/// resulting snippet of the given span.
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// snippet_block(cx, block.span, "..", None)
 +/// // where, `block` is the block of the if expr
 +///     if x {
 +///         y;
 +///     }
 +/// // will return the snippet
 +/// {
 +///     y;
 +/// }
 +/// ```
 +///
 +/// ```rust,ignore
 +/// snippet_block(cx, block.span, "..", Some(if_expr.span))
 +/// // where, `block` is the block of the if expr
 +///     if x {
 +///         y;
 +///     }
 +/// // will return the snippet
 +/// {
 +///         y;
 +///     } // aligned with `if`
 +/// ```
 +/// Note that the first line of the snippet always has 0 indentation.
 +pub fn snippet_block<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +) -> Cow<'a, str> {
 +    let snip = snippet(cx, span, default);
 +    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
 +    trim_multiline(snip, true, indent)
 +}
 +
 +/// Same as `snippet_block`, but adapts the applicability level by the rules of
- // check if expr is calling method or function with #[must_use] attribyte
++/// `snippet_with_applicability`.
 +pub fn snippet_block_with_applicability<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +    applicability: &mut Applicability,
 +) -> Cow<'a, str> {
 +    let snip = snippet_with_applicability(cx, span, default, applicability);
 +    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
 +    trim_multiline(snip, true, indent)
 +}
 +
 +/// Returns a new Span that extends the original Span to the first non-whitespace char of the first
 +/// line.
 +///
 +/// ```rust,ignore
 +///     let x = ();
 +/// //          ^^
 +/// // will be converted to
 +///     let x = ();
 +/// //  ^^^^^^^^^^
 +/// ```
 +pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 +}
 +
 +fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
 +    let line_span = line_span(cx, span);
 +    snippet_opt(cx, line_span).and_then(|snip| {
 +        snip.find(|c: char| !c.is_whitespace())
 +            .map(|pos| line_span.lo() + BytePos::from_usize(pos))
 +    })
 +}
 +
 +/// Returns the indentation of the line of a span
 +///
 +/// ```rust,ignore
 +/// let x = ();
 +/// //      ^^ -- will return 0
 +///     let x = ();
 +/// //          ^^ -- will return 4
 +/// ```
 +pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
 +    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 +}
 +
 +/// Extends the span to the beginning of the spans line, incl. whitespaces.
 +///
 +/// ```rust,ignore
 +///        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::new(line_start, span.hi(), span.ctxt())
 +}
 +
 +/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 +/// Also takes an `Option<String>` which can be put inside the braces.
 +pub fn expr_block<'a, T: LintContext>(
 +    cx: &T,
 +    expr: &Expr<'_>,
 +    option: Option<String>,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +) -> Cow<'a, str> {
 +    let code = snippet_block(cx, expr.span, default, indent_relative_to);
 +    let string = option.unwrap_or_default();
 +    if expr.span.from_expansion() {
 +        Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
 +    } else if let ExprKind::Block(_, _) = expr.kind {
 +        Cow::Owned(format!("{}{}", code, string))
 +    } else if string.is_empty() {
 +        Cow::Owned(format!("{{ {} }}", code))
 +    } else {
 +        Cow::Owned(format!("{{\n{};\n{}\n}}", code, string))
 +    }
 +}
 +
 +/// Trim indentation from a multiline string with possibility of ignoring the
 +/// first line.
 +fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
 +    let s_space = trim_multiline_inner(s, ignore_first, indent, ' ');
 +    let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t');
 +    trim_multiline_inner(s_tab, ignore_first, indent, ' ')
 +}
 +
 +fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>, ch: char) -> Cow<'_, str> {
 +    let mut x = s
 +        .lines()
 +        .skip(ignore_first as usize)
 +        .filter_map(|l| {
 +            if l.is_empty() {
 +                None
 +            } else {
 +                // ignore empty lines
 +                Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0)
 +            }
 +        })
 +        .min()
 +        .unwrap_or(0);
 +    if let Some(indent) = indent {
 +        x = x.saturating_sub(indent);
 +    }
 +    if x > 0 {
 +        Cow::Owned(
 +            s.lines()
 +                .enumerate()
 +                .map(|(i, l)| {
 +                    if (ignore_first && i == 0) || l.is_empty() {
 +                        l
 +                    } else {
 +                        l.split_at(x).1
 +                    }
 +                })
 +                .collect::<Vec<_>>()
 +                .join("\n"),
 +        )
 +    } else {
 +        s
 +    }
 +}
 +
 +/// Gets the parent expression, if any –- this is useful to constrain a lint.
 +pub fn get_parent_expr<'c>(cx: &'c LateContext<'_>, e: &Expr<'_>) -> Option<&'c Expr<'c>> {
 +    let map = &cx.tcx.hir();
 +    let hir_id = e.hir_id;
 +    let parent_id = map.get_parent_node(hir_id);
 +    if hir_id == parent_id {
 +        return None;
 +    }
 +    map.find(parent_id).and_then(|node| {
 +        if let Node::Expr(parent) = node {
 +            Some(parent)
 +        } else {
 +            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(ref block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Returns the base type for HIR references and pointers.
 +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 +    match ty.kind {
 +        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
 +        _ => ty,
 +    }
 +}
 +
 +/// Returns the base type for references and raw pointers.
 +pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
 +    match ty.kind {
 +        ty::Ref(_, ty, _) => walk_ptrs_ty(ty),
 +        _ => ty,
 +    }
 +}
 +
 +/// Returns the base type for references and raw pointers, and count reference
 +/// depth.
 +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
 +        match ty.kind {
 +            ty::Ref(_, ty, _) => inner(ty, depth + 1),
 +            _ => (ty, depth),
 +        }
 +    }
 +    inner(ty, 0)
 +}
 +
 +/// 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 map = cx.tcx.hir();
 +    let parent_item = map.get_parent_item(e.hir_id);
 +    if let Some((Constant::Int(v), _)) = map
 +        .maybe_body_owned_by(parent_item)
 +        .and_then(|body_id| constant(cx, cx.tcx.typeck_body(body_id), e))
 +    {
 +        value == v
 +    } else {
 +        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()
 +}
 +
 +/// Returns the pre-expansion span if is 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,ignore
 +/// foo!(bar!(42));
 +/// ```
 +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 +/// `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)
 +}
 +
++/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
++pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool {
++    ty.walk().any(|inner| match inner.unpack() {
++        GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty),
++        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
++    })
++}
++
 +/// Returns `true` if the given type is an `unsafe` function.
 +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind {
 +        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
 +        _ => false,
 +    }
 +}
 +
 +pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
 +}
 +
 +/// 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 {
 +    fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +        cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
 +    }
 +
 +    if let ExprKind::Call(ref 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,
 +                // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
 +                def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => {
 +                    const_eval::is_const_fn(cx.tcx, def_id)
 +                },
 +                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: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut i: I) -> bool {
 +        i.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(ref pat) | PatKind::Ref(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(ref pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats.iter().map(|pat| &**pat))
 +        },
 +        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
 +        PatKind::Struct(ref qpath, ref fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, ref pats, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
 +        },
 +        PatKind::Slice(ref head, ref middle, ref tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind {
 +                ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived)))
 +}
 +
 +/// Remove blocks around an expression.
 +///
 +/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 +/// themselves.
 +pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 +    while let ExprKind::Block(ref block, ..) = expr.kind {
 +        match (block.stmts.is_empty(), block.expr.as_ref()) {
 +            (true, Some(e)) => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +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_chain! {
 +        if let TyKind::Path(ref qp) = slf.kind;
 +        if let QPath::Resolved(None, ref path) = *qp;
 +        if let Res::SelfTy(..) = path.res;
 +        then {
 +            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>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
 +            if match_qpath(path, &paths::RESULT_OK[1..]);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.kind;
 +            if let Res::Local(lid) = path.res;
 +            if lid == hir_id;
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            match_qpath(path, &paths::RESULT_ERR[1..])
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
 +        if let MatchSource::TryDesugar = *source {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(&arms[0]) && is_err(&arms[1])) ||
 +                (is_ok(&arms[1]) && is_err(&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_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn get_arg_name(pat: &Pat<'_>) -> Option<Symbol> {
 +    match pat.kind {
 +        PatKind::Binding(.., ident, None) => Some(ident.name),
 +        PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
 +        _ => None,
 +    }
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: ast::IntTy) -> u64 {
 +    Integer::from_attr(&tcx, attr::IntType::SignedInt(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: ast::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: ast::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: ast::UintTy) -> u128 {
 +    let bits = Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity)).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +/// Removes block comments from the given `Vec` of lines.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// without_block_comments(vec!["/*", "foo", "*/"]);
 +/// // => vec![]
 +///
 +/// without_block_comments(vec!["bar", "/*", "foo", "*/"]);
 +/// // => vec!["bar"]
 +/// ```
 +pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
 +    let mut without = vec![];
 +
 +    let mut nest_level = 0;
 +
 +    for line in lines {
 +        if line.contains("/*") {
 +            nest_level += 1;
 +            continue;
 +        } else if line.contains("*/") {
 +            nest_level -= 1;
 +            continue;
 +        }
 +
 +        if nest_level == 0 {
 +            without.push(line);
 +        }
 +    }
 +
 +    without
 +}
 +
 +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
 +    let map = &tcx.hir();
 +    let mut prev_enclosing_node = None;
 +    let mut enclosing_node = node;
 +    while Some(enclosing_node) != prev_enclosing_node {
 +        if is_automatically_derived(map.attrs(enclosing_node)) {
 +            return true;
 +        }
 +        prev_enclosing_node = Some(enclosing_node);
 +        enclosing_node = map.get_parent_item(enclosing_node);
 +    }
 +    false
 +}
 +
 +/// Returns true if ty has `iter` or `iter_mut` methods
 +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<&'static str> {
 +    // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
 +    // exists and has the desired signature. Unfortunately FnCtxt is not exported
 +    // so we can't use its `lookup_method` method.
 +    let into_iter_collections: [&[&str]; 13] = [
 +        &paths::VEC,
 +        &paths::OPTION,
 +        &paths::RESULT,
 +        &paths::BTREESET,
 +        &paths::BTREEMAP,
 +        &paths::VEC_DEQUE,
 +        &paths::LINKED_LIST,
 +        &paths::BINARY_HEAP,
 +        &paths::HASHSET,
 +        &paths::HASHMAP,
 +        &paths::PATH_BUF,
 +        &paths::PATH,
 +        &paths::RECEIVER,
 +    ];
 +
 +    let ty_to_check = match probably_ref_ty.kind {
 +        ty::Ref(_, ty_to_check, _) => ty_to_check,
 +        _ => probably_ref_ty,
 +    };
 +
 +    let def_id = match ty_to_check.kind {
 +        ty::Array(..) => return Some("array"),
 +        ty::Slice(..) => return Some("slice"),
 +        ty::Adt(adt, _) => adt.did,
 +        _ => return None,
 +    };
 +
 +    for path in &into_iter_collections {
 +        if match_def_path(cx, def_id, path) {
 +            return Some(*path.last().unwrap());
 +        }
 +    }
 +    None
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, begin_panic_call, &paths::BEGIN_PANIC);
 +/// ```
 +pub fn match_function_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    path: &[&str],
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(ref fun, ref 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 `Ty` is normalizable. This function is useful
 +/// to avoid crashes on `layout_of`.
 +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        let cause = rustc_middle::traits::ObligationCause::dummy();
 +        infcx.at(&cause, param_env).normalize(&ty).is_ok()
 +    })
 +}
 +
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
 +    // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path`
 +    // accepts only that. We should probably move to Symbols in Clippy as well.
 +    let syms = syms.iter().map(|p| Symbol::intern(p)).collect::<Vec<Symbol>>();
 +    cx.match_def_path(did, &syms)
 +}
 +
 +/// 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>,
 +) -> (SmallVec<[&'tcx Expr<'tcx>; 1]>, SmallVec<[&'tcx Block<'tcx>; 1]>) {
 +    let mut conds = SmallVec::new();
 +    let mut blocks: SmallVec<[&Block<'_>; 1]> = SmallVec::new();
 +
 +    while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) {
 +        conds.push(&**cond);
 +        if let ExprKind::Block(ref block, _) = then_expr.kind {
 +            blocks.push(block);
 +        } else {
 +            panic!("ExprKind::If node is not an ExprKind::Block");
 +        }
 +
 +        if let Some(ref else_expr) = *else_expr {
 +            expr = else_expr;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    // final `else {..}`
 +    if !blocks.is_empty() {
 +        if let ExprKind::Block(ref block, _) = expr.kind {
 +            blocks.push(&**block);
 +        }
 +    }
 +
 +    (conds, blocks)
 +}
 +
 +pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
 +    let map = cx.tcx.hir();
 +    let parent_id = map.get_parent_node(expr.hir_id);
 +    let parent_node = map.get(parent_id);
 +
 +    match parent_node {
 +        Node::Expr(e) => higher::if_block(&e).is_some(),
 +        Node::Arm(e) => higher::if_block(&e.body).is_some(),
 +        _ => false,
 +    }
 +}
 +
 +// Finds the attribute with the given name, if any
 +pub fn attr_by_name<'a>(attrs: &'a [Attribute], name: &'_ str) -> Option<&'a Attribute> {
 +    attrs
 +        .iter()
 +        .find(|attr| attr.ident().map_or(false, |ident| ident.as_str() == name))
 +}
 +
 +// Finds the `#[must_use]` attribute, if any
 +pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 +    attr_by_name(attrs, "must_use")
 +}
 +
 +// Returns whether the type has #[must_use] attribute
 +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind {
 +        ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
 +        ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
 +        ty::Slice(ref ty)
 +        | ty::Array(ref ty, _)
 +        | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
 +        | ty::Ref(_, ref ty, _) => {
 +            // for the Array case we don't need to care for the len == 0 case
 +            // because we don't want to lint functions returning empty arrays
 +            is_must_use_ty(cx, *ty)
 +        },
 +        ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
 +        ty::Opaque(ref def_id, _) => {
 +            for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates {
 +                if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() {
 +                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        ty::Dynamic(binder, _) => {
 +            for predicate in binder.skip_binder().iter() {
 +                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
 +                    if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        _ => false,
 +    }
 +}
 +
- /// Returns true iff the given expression is a slice of primitives (as defined in the
- /// `is_recursively_primitive_type` function).
- pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
++// 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(ref 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())
 +}
 +
 +pub fn is_no_std_crate(krate: &Crate<'_>) -> bool {
 +    krate.item.attrs.iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr) = attr.kind {
 +            attr.path == symbol::sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
 +/// ```rust,ignore
 +/// 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{ of_trait: Some(_), .. })
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates =
 +        cx.tcx
 +            .predicates_of(did)
 +            .predicates
 +            .iter()
 +            .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
 +    traits::impossible_predicates(
 +        cx.tcx,
 +        traits::elaborate_predicates(cx.tcx, predicates)
 +            .map(|o| o.predicate)
 +            .collect::<Vec<_>>(),
 +    )
 +}
 +
 +/// Returns the `DefId` of the callee if the given expression is a function or method call.
 +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 +    match &expr.kind {
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(qpath),
 +                ..
 +            },
 +            ..,
 +        ) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(),
 +        _ => None,
 +    }
 +}
 +
 +pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool {
 +    lints.iter().any(|lint| {
 +        matches!(
 +            cx.tcx.lint_level_at_node(lint, id),
 +            (Level::Forbid | Level::Deny | Level::Warn, _)
 +        )
 +    })
 +}
 +
 +/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point
 +/// number type, a str, or an array, slice, or tuple of those types).
 +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 +    match ty.kind {
 +        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
 +        ty::Ref(_, inner, _) if inner.kind == ty::Str => true,
 +        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
 +        ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
 +        _ => false,
 +    }
 +}
 +
-     match expr_type.kind {
++/// 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 {
 +        ty::Slice(ref element_type)
 +        | ty::Ref(
 +            _,
 +            ty::TyS {
 +                kind: ty::Slice(ref element_type),
 +                ..
 +            },
 +            _,
 +        ) => is_recursively_primitive_type(element_type),
 +        _ => false,
++    };
++
++    if is_primitive {
++        // if we have wrappers like Array, Slice or Tuple, print these
++        // and get the type enclosed in the slice ref
++        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind {
++            ty::Slice(..) => return Some("slice".into()),
++            ty::Array(..) => return Some("array".into()),
++            ty::Tuple(..) => return Some("tuple".into()),
++            _ => {
++                // is_recursively_primitive_type() should have taken care
++                // of the rest and we can rely on the type that is found
++                let refs_peeled = expr_type.peel_refs();
++                return Some(refs_peeled.walk().last().unwrap().to_string());
++            },
++        }
 +    }
++    None
 +}
 +
 +#[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;
 +            },
 +        }
 +    }};
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::{trim_multiline, without_block_comments};
 +
 +    #[test]
 +    fn test_trim_multiline_single_line() {
 +        assert_eq!("", trim_multiline("".into(), false, None));
 +        assert_eq!("...", trim_multiline("...".into(), false, None));
 +        assert_eq!("...", trim_multiline("    ...".into(), false, None));
 +        assert_eq!("...", trim_multiline("\t...".into(), false, None));
 +        assert_eq!("...", trim_multiline("\t\t...".into(), false, None));
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn test_trim_multiline_block() {
 +        assert_eq!("\
 +    if x {
 +        y
 +    } else {
 +        z
 +    }", trim_multiline("    if x {
 +            y
 +        } else {
 +            z
 +        }".into(), false, None));
 +        assert_eq!("\
 +    if x {
 +    \ty
 +    } else {
 +    \tz
 +    }", trim_multiline("    if x {
 +        \ty
 +        } else {
 +        \tz
 +        }".into(), false, None));
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn test_trim_multiline_empty_line() {
 +        assert_eq!("\
 +    if x {
 +        y
 +
 +    } else {
 +        z
 +    }", trim_multiline("    if x {
 +            y
 +
 +        } else {
 +            z
 +        }".into(), false, None));
 +    }
 +
 +    #[test]
 +    fn test_without_block_comments_lines_without_block_comments() {
 +        let result = without_block_comments(vec!["/*", "", "*/"]);
 +        println!("result: {:?}", result);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
 +        assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
 +
 +        let result = without_block_comments(vec!["/* rust", "", "*/"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* one-line comment */"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["foo", "bar", "baz"]);
 +        assert_eq!(result, vec!["foo", "bar", "baz"]);
 +    }
 +}
index 9c28d63d414c525b2ae5e3013be44ab07fef0255,0000000000000000000000000000000000000000..d44854aefe97acfd2c3943657ac107e428ecde8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,130 -1,0 +1,133 @@@
 +//! This module contains paths to types and functions Clippy needs to know
 +//! about.
 +//!
 +//! Whenever possible, please consider diagnostic items over hardcoded paths.
 +//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 +
 +pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
 +pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
 +pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
 +pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
 +pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
 +pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
 +pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
 +pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
 +pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
 +pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
 +pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
 +pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
 +pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
 +pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 +pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
 +pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
 +pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
 +pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"];
 +pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
 +pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
 +pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
 +pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
 +pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
 +pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
 +pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
 +pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
 +pub const DROP: [&str; 3] = ["core", "mem", "drop"];
 +pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
 +pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
 +pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
 +pub const EXIT: [&str; 3] = ["std", "process", "exit"];
++pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"];
++pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"];
 +pub const FILE: [&str; 3] = ["std", "fs", "File"];
 +pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
 +pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
 +pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
 +pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
 +pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 +pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
 +pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 +pub const HASH: [&str; 2] = ["hash", "Hash"];
 +pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
 +pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 +pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
 +pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
 +pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
 +pub const INTO: [&str; 3] = ["core", "convert", "Into"];
 +pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
 +pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
 +pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
 +pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
 +pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
 +pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
 +pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
 +pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
 +pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
 +pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
 +pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
 +pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
 +pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
 +pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
 +pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
 +pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
 +pub const OPTION: [&str; 3] = ["core", "option", "Option"];
 +pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
 +pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
 +pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
 +pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
 +pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
 +pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
 +pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
 +pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
 +pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
 +pub const PATH: [&str; 3] = ["std", "path", "Path"];
 +pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
 +pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 +pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 +pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 +pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 +pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 +pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
++pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 +pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 +pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 +pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 +pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
 +pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
 +pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
 +pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
 +pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
 +pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
 +pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
 +pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
 +pub const RESULT: [&str; 3] = ["core", "result", "Result"];
 +pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
 +pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
 +pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
 +pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
 +pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
 +pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 +pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 +pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
 +pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 +pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 +pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
 +pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
 +pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
 +pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
 +pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
 +pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 +pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
 +pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 +pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
 +pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 +pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
 +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 +pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
 +pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
 +pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
 +pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 +pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
 +pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 +pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
 +pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 +pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 +pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
index f2e76442a19bae5775d72f5343183bf10ac4066f,0000000000000000000000000000000000000000..84e907d7125de8951f291dc201a4c453d417c74d
mode 100644,000000..100644
--- /dev/null
@@@ -1,112 -1,0 +1,135 @@@
- use crate::consts::constant;
++use crate::consts::{constant, Constant};
++use crate::rustc_target::abi::LayoutOf;
 +use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BorrowKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, Ty};
- use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +
++#[allow(clippy::module_name_repetitions)]
++#[derive(Copy, Clone)]
++pub struct UselessVec {
++    pub too_large_for_stack: u64,
++}
++
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
 +    /// be possible.
 +    ///
 +    /// **Why is this bad?** This is less efficient.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # fn foo(my_vec: &[u8]) {}
 +    ///
 +    /// // Bad
 +    /// foo(&vec![1, 2]);
 +    ///
 +    /// // Good
 +    /// foo(&[1, 2]);
 +    /// ```
 +    pub USELESS_VEC,
 +    perf,
 +    "useless `vec!`"
 +}
 +
- declare_lint_pass!(UselessVec => [USELESS_VEC]);
++impl_lint_pass!(UselessVec => [USELESS_VEC]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UselessVec {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
 +        if_chain! {
 +            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind;
 +            if let ty::Slice(..) = ty.kind;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
 +            if let Some(vec_args) = higher::vec_macro(cx, addressee);
 +            then {
-                 check_vec_macro(cx, &vec_args, expr.span);
++                self.check_vec_macro(cx, &vec_args, expr.span);
 +            }
 +        }
 +
 +        // search for `for _ in vec![…]`
 +        if_chain! {
 +            if let Some((_, arg, _)) = higher::for_loop(expr);
 +            if let Some(vec_args) = higher::vec_macro(cx, arg);
 +            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
 +            then {
 +                // report the error around the `vec!` not inside `<std macros>:`
 +                let span = arg.span
 +                    .ctxt()
 +                    .outer_expn_data()
 +                    .call_site
 +                    .ctxt()
 +                    .outer_expn_data()
 +                    .call_site;
-                 check_vec_macro(cx, &vec_args, span);
++                self.check_vec_macro(cx, &vec_args, span);
 +            }
 +        }
 +    }
 +}
 +
- fn check_vec_macro<'tcx>(cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
-     let mut applicability = Applicability::MachineApplicable;
-     let snippet = match *vec_args {
-         higher::VecArgs::Repeat(elem, len) => {
-             if constant(cx, cx.typeck_results(), len).is_some() {
-                 format!(
-                     "&[{}; {}]",
-                     snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
-                     snippet_with_applicability(cx, len.span, "len", &mut applicability)
-                 )
-             } else {
-                 return;
-             }
-         },
-         higher::VecArgs::Vec(args) => {
-             if let Some(last) = args.iter().last() {
-                 let span = args[0].span.to(last.span);
++impl UselessVec {
++    fn check_vec_macro<'tcx>(self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
++        let mut applicability = Applicability::MachineApplicable;
++        let snippet = match *vec_args {
++            higher::VecArgs::Repeat(elem, len) => {
++                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
++                    #[allow(clippy::cast_possible_truncation)]
++                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
++                        return;
++                    }
 +
-                 format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
-             } else {
-                 "&[]".into()
-             }
-         },
-     };
++                    format!(
++                        "&[{}; {}]",
++                        snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
++                        snippet_with_applicability(cx, len.span, "len", &mut applicability)
++                    )
++                } else {
++                    return;
++                }
++            },
++            higher::VecArgs::Vec(args) => {
++                if let Some(last) = args.iter().last() {
++                    #[allow(clippy::cast_possible_truncation)]
++                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
++                        return;
++                    }
++                    let span = args[0].span.to(last.span);
++
++                    format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
++                } else {
++                    "&[]".into()
++                }
++            },
++        };
++
++        span_lint_and_sugg(
++            cx,
++            USELESS_VEC,
++            span,
++            "useless use of `vec!`",
++            "you can use a slice directly",
++            snippet,
++            applicability,
++        );
++    }
++}
 +
-     span_lint_and_sugg(
-         cx,
-         USELESS_VEC,
-         span,
-         "useless use of `vec!`",
-         "you can use a slice directly",
-         snippet,
-         applicability,
-     );
++fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
++    let ty = cx.typeck_results().expr_ty_adjusted(expr);
++    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
 +}
 +
 +/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
 +fn vec_type(ty: Ty<'_>) -> Ty<'_> {
 +    if let ty::Adt(_, substs) = ty.kind {
 +        substs.type_at(0)
 +    } else {
 +        panic!("The type of `vec!` is a not a struct?");
 +    }
 +}
index e7eb7c2e9802d05c249f9e9ebe8f4cbb633c7b40,0000000000000000000000000000000000000000..5683a71efea4eff68208fd420aeda4c0d95b73d5
mode 100644,000000..100644
--- /dev/null
@@@ -1,214 -1,0 +1,211 @@@
- // Allow "...prelude::*" imports.
 +use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    def::{DefKind, Res},
 +    Item, ItemKind, PathSegment, UseKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::BytePos;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `use Enum::*`.
 +    ///
 +    /// **Why is this bad?** It is usually better style to use the prefixed name of
 +    /// an enumeration variant, rather than importing variants.
 +    ///
 +    /// **Known problems:** Old-style enumerations that prefix the variants are
 +    /// still around.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// use std::cmp::Ordering::*;
 +    /// foo(Less);
 +    ///
 +    /// // Good
 +    /// use std::cmp::Ordering;
 +    /// foo(Ordering::Less)
 +    /// ```
 +    pub ENUM_GLOB_USE,
 +    pedantic,
 +    "use items that import all variants of an enum"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for wildcard imports `use _::*`.
 +    ///
 +    /// **Why is this bad?** wildcard imports can pollute the namespace. This is especially bad if
 +    /// you try to import something through a wildcard, that already has been imported by name from
 +    /// a different source:
 +    ///
 +    /// ```rust,ignore
 +    /// use crate1::foo; // Imports a function named foo
 +    /// use crate2::*; // Has a function named foo
 +    ///
 +    /// foo(); // Calls crate1::foo
 +    /// ```
 +    ///
 +    /// This can lead to confusing error messages at best and to unexpected behavior at worst.
 +    ///
 +    /// **Exceptions:**
 +    ///
 +    /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
 +    /// provide modules named "prelude" specifically designed for wildcard import.
 +    ///
 +    /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
 +    ///
 +    /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
 +    ///
 +    /// **Known problems:** If macros are imported through the wildcard, this macro is not included
 +    /// by the suggestion and has to be added by hand.
 +    ///
 +    /// Applying the suggestion when explicit imports of the things imported with a glob import
 +    /// exist, may result in `unused_imports` warnings.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// use crate1::*;
 +    ///
 +    /// foo();
 +    /// ```
 +    ///
 +    /// ```rust,ignore
 +    /// // Good
 +    /// use crate1::foo;
 +    ///
 +    /// foo();
 +    /// ```
 +    pub WILDCARD_IMPORTS,
 +    pedantic,
 +    "lint `use _::*` statements"
 +}
 +
 +#[derive(Default)]
 +pub struct WildcardImports {
 +    warn_on_all: bool,
 +    test_modules_deep: u32,
 +}
 +
 +impl WildcardImports {
 +    pub fn new(warn_on_all: bool) -> Self {
 +        Self {
 +            warn_on_all,
 +            test_modules_deep: 0,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 +
 +impl LateLintPass<'_> for WildcardImports {
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        if is_test_module_or_function(item) {
 +            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
 +        }
 +        if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
 +            return;
 +        }
 +        if_chain! {
 +            if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
 +            if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
 +            let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner);
 +            if !used_imports.is_empty(); // Already handled by `unused_imports`
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
 +                let (span, braced_glob) = if import_source_snippet.is_empty() {
 +                    // This is a `_::{_, *}` import
 +                    // In this case `use_path.span` is empty and ends directly in front of the `*`,
 +                    // so we need to extend it by one byte.
 +                    (
 +                        use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
 +                        true,
 +                    )
 +                } else {
 +                    // In this case, the `use_path.span` ends right before the `::*`, so we need to
 +                    // extend it up to the `*`. Since it is hard to find the `*` in weird
 +                    // formattings like `use _ ::  *;`, we extend it up to, but not including the
 +                    // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
 +                    // can just use the end of the item span
 +                    let mut span = use_path.span.with_hi(item.span.hi());
 +                    if snippet(cx, span, "").ends_with(';') {
 +                        span = use_path.span.with_hi(item.span.hi() - BytePos(1));
 +                    }
 +                    (
 +                        span, false,
 +                    )
 +                };
 +
 +                let imports_string = if used_imports.len() == 1 {
 +                    used_imports.iter().next().unwrap().to_string()
 +                } else {
 +                    let mut imports = used_imports
 +                        .iter()
 +                        .map(ToString::to_string)
 +                        .collect::<Vec<_>>();
 +                    imports.sort();
 +                    if braced_glob {
 +                        imports.join(", ")
 +                    } else {
 +                        format!("{{{}}}", imports.join(", "))
 +                    }
 +                };
 +
 +                let sugg = if braced_glob {
 +                    imports_string
 +                } else {
 +                    format!("{}::{}", import_source_snippet, imports_string)
 +                };
 +
 +                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
 +                    (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
 +                } else {
 +                    (WILDCARD_IMPORTS, "usage of wildcard import")
 +                };
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    lint,
 +                    span,
 +                    message,
 +                    "try",
 +                    sugg,
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
 +        if is_test_module_or_function(item) {
 +            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
 +        }
 +    }
 +}
 +
 +impl WildcardImports {
 +    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
 +        in_macro(item.span)
 +            || is_prelude_import(segments)
 +            || (is_super_only_import(segments) && self.test_modules_deep > 0)
 +    }
 +}
 +
-     segments
-         .iter()
-         .last()
-         .map_or(false, |ps| ps.ident.as_str() == "prelude")
++// Allow "...prelude::..::*" imports.
 +// Many crates have a prelude, and it is imported as a glob by design.
 +fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
++    segments.iter().any(|ps| ps.ident.as_str() == "prelude")
 +}
 +
 +// Allow "super::*" imports in tests.
 +fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
 +    segments.len() == 1 && segments[0].ident.as_str() == "super"
 +}
 +
 +fn is_test_module_or_function(item: &Item<'_>) -> bool {
 +    matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
 +}
index 063f94582b9d14cc38f138d8914e8ce178aaae66,0000000000000000000000000000000000000000..e653240d049170b61d4755cd964185195e2edce7
mode 100644,000000..100644
--- /dev/null
@@@ -1,510 -1,0 +1,505 @@@
-             if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), false) {
 +use std::borrow::Cow;
 +use std::ops::Range;
 +
 +use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
 +use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, MacCall, StrLit, StrStyle};
 +use rustc_ast::token;
 +use rustc_ast::tokenstream::TokenStream;
 +use rustc_errors::Applicability;
 +use rustc_lexer::unescape::{self, EscapeError};
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_parse::parser;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::Symbol;
 +use rustc_span::{BytePos, Span};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `println!("")` to
 +    /// print a newline.
 +    ///
 +    /// **Why is this bad?** You should use `println!()`, which is simpler.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// // Bad
 +    /// println!("");
 +    ///
 +    /// // Good
 +    /// println!();
 +    /// ```
 +    pub PRINTLN_EMPTY_STRING,
 +    style,
 +    "using `println!(\"\")` with an empty string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `print!()` with a format
 +    /// string that ends in a newline.
 +    ///
 +    /// **Why is this bad?** You should use `println!()` instead, which appends the
 +    /// newline.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let name = "World";
 +    /// print!("Hello {}!\n", name);
 +    /// ```
 +    /// use println!() instead
 +    /// ```rust
 +    /// # let name = "World";
 +    /// println!("Hello {}!", name);
 +    /// ```
 +    pub PRINT_WITH_NEWLINE,
 +    style,
 +    "using `print!()` with a format string that ends in a single newline"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for printing on *stdout*. The purpose of this lint
 +    /// is to catch debugging remnants.
 +    ///
 +    /// **Why is this bad?** People often print on *stdout* while debugging an
 +    /// application and might forget to remove those prints afterward.
 +    ///
 +    /// **Known problems:** Only catches `print!` and `println!` calls.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// println!("Hello world!");
 +    /// ```
 +    pub PRINT_STDOUT,
 +    restriction,
 +    "printing on stdout"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `Debug` formatting. The purpose of this
 +    /// lint is to catch debugging remnants.
 +    ///
 +    /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
 +    /// debugging Rust code. It should not be used in user-facing output.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let foo = "bar";
 +    /// println!("{:?}", foo);
 +    /// ```
 +    pub USE_DEBUG,
 +    restriction,
 +    "use of `Debug`-based formatting"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
 +    ///
 +    /// **Why is this bad?** Using literals as `println!` args is inefficient
 +    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
 +    /// (i.e., just put the literal in the format string)
 +    ///
 +    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
 +    /// -- e.g., `println!("{}", env!("FOO"))`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// println!("{}", "foo");
 +    /// ```
 +    /// use the literal without formatting:
 +    /// ```rust
 +    /// println!("foo");
 +    /// ```
 +    pub PRINT_LITERAL,
 +    style,
 +    "printing a literal with a format string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `writeln!(buf, "")` to
 +    /// print a newline.
 +    ///
 +    /// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    ///
 +    /// // Bad
 +    /// writeln!(buf, "");
 +    ///
 +    /// // Good
 +    /// writeln!(buf);
 +    /// ```
 +    pub WRITELN_EMPTY_STRING,
 +    style,
 +    "using `writeln!(buf, \"\")` with an empty string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `write!()` with a format
 +    /// string that
 +    /// ends in a newline.
 +    ///
 +    /// **Why is this bad?** You should use `writeln!()` instead, which appends the
 +    /// newline.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    /// # let name = "World";
 +    ///
 +    /// // Bad
 +    /// write!(buf, "Hello {}!\n", name);
 +    ///
 +    /// // Good
 +    /// writeln!(buf, "Hello {}!", name);
 +    /// ```
 +    pub WRITE_WITH_NEWLINE,
 +    style,
 +    "using `write!()` with a format string that ends in a single newline"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
 +    ///
 +    /// **Why is this bad?** Using literals as `writeln!` args is inefficient
 +    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
 +    /// (i.e., just put the literal in the format string)
 +    ///
 +    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
 +    /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    ///
 +    /// // Bad
 +    /// writeln!(buf, "{}", "foo");
 +    ///
 +    /// // Good
 +    /// writeln!(buf, "foo");
 +    /// ```
 +    pub WRITE_LITERAL,
 +    style,
 +    "writing a literal with a format string"
 +}
 +
 +#[derive(Default)]
 +pub struct Write {
 +    in_debug_impl: bool,
 +}
 +
 +impl_lint_pass!(Write => [
 +    PRINT_WITH_NEWLINE,
 +    PRINTLN_EMPTY_STRING,
 +    PRINT_STDOUT,
 +    USE_DEBUG,
 +    PRINT_LITERAL,
 +    WRITE_WITH_NEWLINE,
 +    WRITELN_EMPTY_STRING,
 +    WRITE_LITERAL
 +]);
 +
 +impl EarlyLintPass for Write {
 +    fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
 +        if let ItemKind::Impl {
 +            of_trait: Some(trait_ref),
 +            ..
 +        } = &item.kind
 +        {
 +            let trait_name = trait_ref
 +                .path
 +                .segments
 +                .iter()
 +                .last()
 +                .expect("path has at least one segment")
 +                .ident
 +                .name;
 +            if trait_name == sym!(Debug) {
 +                self.in_debug_impl = true;
 +            }
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
 +        self.in_debug_impl = false;
 +    }
 +
 +    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
 +        if mac.path == sym!(println) {
 +            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
-             if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), false) {
++            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
 +                if fmt_str.symbol == Symbol::intern("") {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        PRINTLN_EMPTY_STRING,
 +                        mac.span(),
 +                        "using `println!(\"\")`",
 +                        "replace it with",
 +                        "println!()".to_string(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        } else if mac.path == sym!(print) {
 +            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
-             if let (Some(fmt_str), _) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
++            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
 +                if check_newlines(&fmt_str) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PRINT_WITH_NEWLINE,
 +                        mac.span(),
 +                        "using `print!()` with a format string that ends in a single newline",
 +                        |err| {
 +                            err.multipart_suggestion(
 +                                "use `println!` instead",
 +                                vec![
 +                                    (mac.path.span, String::from("println")),
 +                                    (newline_span(&fmt_str), String::new()),
 +                                ],
 +                                Applicability::MachineApplicable,
 +                            );
 +                        },
 +                    );
 +                }
 +            }
 +        } else if mac.path == sym!(write) {
-             if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
++            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
 +                if check_newlines(&fmt_str) {
 +                    span_lint_and_then(
 +                        cx,
 +                        WRITE_WITH_NEWLINE,
 +                        mac.span(),
 +                        "using `write!()` with a format string that ends in a single newline",
 +                        |err| {
 +                            err.multipart_suggestion(
 +                                "use `writeln!()` instead",
 +                                vec![
 +                                    (mac.path.span, String::from("writeln")),
 +                                    (newline_span(&fmt_str), String::new()),
 +                                ],
 +                                Applicability::MachineApplicable,
 +                            );
 +                        },
 +                    )
 +                }
 +            }
 +        } else if mac.path == sym!(writeln) {
-                     let suggestion = expr.map_or_else(
-                         || {
-                             applicability = Applicability::HasPlaceholders;
-                             Cow::Borrowed("v")
-                         },
-                         |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable),
-                     );
++            if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
 +                if fmt_str.symbol == Symbol::intern("") {
 +                    let mut applicability = Applicability::MachineApplicable;
-     fn check_tts<'a>(
-         &self,
-         cx: &EarlyContext<'a>,
-         tts: &TokenStream,
-         is_write: bool,
-     ) -> (Option<StrLit>, Option<Expr>) {
++                    // FIXME: remove this `#[allow(...)]` once the issue #5822 gets fixed
++                    #[allow(clippy::option_if_let_else)]
++                    let suggestion = if let Some(e) = expr {
++                        snippet_with_applicability(cx, e.span, "v", &mut applicability)
++                    } else {
++                        applicability = Applicability::HasPlaceholders;
++                        Cow::Borrowed("v")
++                    };
 +
 +                    span_lint_and_sugg(
 +                        cx,
 +                        WRITELN_EMPTY_STRING,
 +                        mac.span(),
 +                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
 +                        "replace it with",
 +                        format!("writeln!({})", suggestion),
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Given a format string that ends in a newline and its span, calculates the span of the
 +/// newline.
 +fn newline_span(fmtstr: &StrLit) -> Span {
 +    let sp = fmtstr.span;
 +    let contents = &fmtstr.symbol.as_str();
 +
 +    let newline_sp_hi = sp.hi()
 +        - match fmtstr.style {
 +            StrStyle::Cooked => BytePos(1),
 +            StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
 +        };
 +
 +    let newline_sp_len = if contents.ends_with('\n') {
 +        BytePos(1)
 +    } else if contents.ends_with(r"\n") {
 +        BytePos(2)
 +    } else {
 +        panic!("expected format string to contain a newline");
 +    };
 +
 +    sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi)
 +}
 +
 +impl Write {
 +    /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
 +    /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
 +    /// the contents of the string, whether it's a raw string, and the span of the literal in the
 +    /// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
 +    /// `format_str` should be written to.
 +    ///
 +    /// Example:
 +    ///
 +    /// Calling this function on
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    /// # let something = "something";
 +    /// writeln!(buf, "string to write: {}", something);
 +    /// ```
 +    /// will return
 +    /// ```rust,ignore
 +    /// (Some("string to write: {}"), Some(buf))
 +    /// ```
 +    #[allow(clippy::too_many_lines)]
-         let tts = tts.clone();
++    fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
 +        use rustc_parse_format::{
 +            AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser,
 +            Piece,
 +        };
 +
 +        let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
 +        let mut expr: Option<Expr> = None;
 +        if is_write {
 +            expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
 +                Ok(p) => Some(p.into_inner()),
 +                Err(_) => return (None, None),
 +            };
 +            // might be `writeln!(foo)`
 +            if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
 +                return (None, expr);
 +            }
 +        }
 +
 +        let fmtstr = match parser.parse_str_lit() {
 +            Ok(fmtstr) => fmtstr,
 +            Err(_) => return (None, expr),
 +        };
 +        let tmp = fmtstr.symbol.as_str();
 +        let mut args = vec![];
 +        let mut fmt_parser = Parser::new(&tmp, None, None, false, ParseMode::Format);
 +        while let Some(piece) = fmt_parser.next() {
 +            if !fmt_parser.errors.is_empty() {
 +                return (None, expr);
 +            }
 +            if let Piece::NextArgument(arg) = piece {
 +                if !self.in_debug_impl && arg.format.ty == "?" {
 +                    // FIXME: modify rustc's fmt string parser to give us the current span
 +                    span_lint(cx, USE_DEBUG, parser.prev_token.span, "use of `Debug`-based formatting");
 +                }
 +                args.push(arg);
 +            }
 +        }
 +        let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
 +        let mut idx = 0;
 +        loop {
 +            const SIMPLE: FormatSpec<'_> = FormatSpec {
 +                fill: None,
 +                align: AlignUnknown,
 +                flags: 0,
 +                precision: CountImplied,
 +                precision_span: None,
 +                width: CountImplied,
 +                width_span: None,
 +                ty: "",
 +                ty_span: None,
 +            };
 +            if !parser.eat(&token::Comma) {
 +                return (Some(fmtstr), expr);
 +            }
 +            let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) {
 +                expr
 +            } else {
 +                return (Some(fmtstr), None);
 +            };
 +            match &token_expr.kind {
 +                ExprKind::Lit(_) => {
 +                    let mut all_simple = true;
 +                    let mut seen = false;
 +                    for arg in &args {
 +                        match arg.position {
 +                            ArgumentImplicitlyIs(n) | ArgumentIs(n) => {
 +                                if n == idx {
 +                                    all_simple &= arg.format == SIMPLE;
 +                                    seen = true;
 +                                }
 +                            },
 +                            ArgumentNamed(_) => {},
 +                        }
 +                    }
 +                    if all_simple && seen {
 +                        span_lint(cx, lint, token_expr.span, "literal with an empty format string");
 +                    }
 +                    idx += 1;
 +                },
 +                ExprKind::Assign(lhs, rhs, _) => {
 +                    if let ExprKind::Lit(_) = rhs.kind {
 +                        if let ExprKind::Path(_, p) = &lhs.kind {
 +                            let mut all_simple = true;
 +                            let mut seen = false;
 +                            for arg in &args {
 +                                match arg.position {
 +                                    ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
 +                                    ArgumentNamed(name) => {
 +                                        if *p == name {
 +                                            seen = true;
 +                                            all_simple &= arg.format == SIMPLE;
 +                                        }
 +                                    },
 +                                }
 +                            }
 +                            if all_simple && seen {
 +                                span_lint(cx, lint, rhs.span, "literal with an empty format string");
 +                            }
 +                        }
 +                    }
 +                },
 +                _ => idx += 1,
 +            }
 +        }
 +    }
 +}
 +
 +/// Checks if the format string contains a single newline that terminates it.
 +///
 +/// Literal and escaped newlines are both checked (only literal for raw strings).
 +fn check_newlines(fmtstr: &StrLit) -> bool {
 +    let mut has_internal_newline = false;
 +    let mut last_was_cr = false;
 +    let mut should_lint = false;
 +
 +    let contents = &fmtstr.symbol.as_str();
 +
 +    let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
 +        let c = c.unwrap();
 +
 +        if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
 +            should_lint = true;
 +        } else {
 +            last_was_cr = c == '\r';
 +            if c == '\n' {
 +                has_internal_newline = true;
 +            }
 +        }
 +    };
 +
 +    match fmtstr.style {
 +        StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
 +        StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
 +    }
 +
 +    should_lint
 +}
index 168092f7329cc0caed65ea30f0edfe20ac91644c,0000000000000000000000000000000000000000..3c782e9b17ff15c0db0947b54b766aa52f8326ef
mode 100644,000000..100644
--- /dev/null
@@@ -1,497 -1,0 +1,503 @@@
 +# Adding a new lint
 +
 +You are probably here because you want to add a new lint to Clippy. If this is
 +the first time you're contributing to Clippy, this document guides you through
 +creating an example lint from scratch.
 +
 +To get started, we will create a lint that detects functions called `foo`,
 +because that's clearly a non-descriptive name.
 +
 +- [Adding a new lint](#adding-a-new-lint)
 +  - [Setup](#setup)
 +  - [Getting Started](#getting-started)
 +  - [Testing](#testing)
 +  - [Rustfix tests](#rustfix-tests)
 +  - [Edition 2018 tests](#edition-2018-tests)
 +  - [Testing manually](#testing-manually)
 +  - [Lint declaration](#lint-declaration)
 +  - [Lint passes](#lint-passes)
 +  - [Emitting a lint](#emitting-a-lint)
 +  - [Adding the lint logic](#adding-the-lint-logic)
 +  - [Author lint](#author-lint)
 +  - [Documentation](#documentation)
 +  - [Running rustfmt](#running-rustfmt)
 +  - [Debugging](#debugging)
 +  - [PR Checklist](#pr-checklist)
 +  - [Cheatsheet](#cheatsheet)
 +
 +## Setup
 +
 +See the [Basics](basics.md#get-the-code) documentation.
 +
 +## Getting Started
 +
 +There is a bit of boilerplate code that needs to be set up when creating a new
 +lint. Fortunately, you can use the clippy dev tools to handle this for you. We
 +are naming our new lint `foo_functions` (lints are generally written in snake
 +case), and we don't need type information so it will have an early pass type
 +(more on this later on). If you're not sure if the name you chose fits the lint,
 +take a look at our [lint naming guidelines][lint_naming]. To get started on this
 +lint you can run `cargo dev new_lint --name=foo_functions --pass=early
 +--category=pedantic` (category will default to nursery if not provided). This
 +command will create two files: `tests/ui/foo_functions.rs` and
 +`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
 +register the new lint. For cargo lints, two project hierarchies (fail/pass) will
 +be created by default under `tests/ui-cargo`.
 +
 +Next, we'll open up these files and add our lint!
 +
 +## Testing
 +
 +Let's write some tests first that we can execute while we iterate on our lint.
 +
 +Clippy uses UI tests for testing. UI tests check that the output of Clippy is
 +exactly as expected. Each test is just a plain Rust file that contains the code
 +we want to check. The output of Clippy is compared against a `.stderr` file.
 +Note that you don't have to create this file yourself, we'll get to
 +generating the `.stderr` files further down.
 +
 +We start by opening the test file created at `tests/ui/foo_functions.rs`.
 +
 +Update the file with some examples to get started:
 +
 +```rust
 +#![warn(clippy::foo_functions)]
 +
 +// Impl methods
 +struct A;
 +impl A {
 +    pub fn fo(&self) {}
 +    pub fn foo(&self) {}
 +    pub fn food(&self) {}
 +}
 +
 +// Default trait methods
 +trait B {
 +    fn fo(&self) {}
 +    fn foo(&self) {}
 +    fn food(&self) {}
 +}
 +
 +// Plain functions
 +fn fo() {}
 +fn foo() {}
 +fn food() {}
 +
 +fn main() {
 +    // We also don't want to lint method calls
 +    foo();
 +    let a = A;
 +    a.foo();
 +}
 +```
 +
 +Now we can run the test with `TESTNAME=foo_functions cargo uitest`,
 +currently this test is meaningless though.
 +
 +While we are working on implementing our lint, we can keep running the UI
 +test. That allows us to check if the output is turning into what we want.
 +
 +Once we are satisfied with the output, we need to run
 +`tests/ui/update-all-references.sh` to update the `.stderr` file for our lint.
 +Please note that, we should run `TESTNAME=foo_functions cargo uitest`
 +every time before running `tests/ui/update-all-references.sh`.
 +Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
 +our lint, we need to commit the generated `.stderr` files, too. In general, you
 +should only commit files changed by `tests/ui/update-all-references.sh` for the
 +specific lint you are creating/editing.
 +
 +### Cargo lints
 +
 +For cargo lints, the process of testing differs in that we are interested in
 +the `Cargo.toml` manifest file. We also need a minimal crate associated
 +with that manifest.
 +
 +If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint`
 +we will find by default two new crates, each with its manifest file:
 +
 +* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error.
 +* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger the lint.
 +
 +If you need more cases, you can copy one of those crates (under `foo_categories`) and rename it.
 +
 +The process of generating the `.stderr` file is the same, and prepending the `TESTNAME`
 +variable to `cargo uitest` works too, but the script to update the references
 +is in another path: `tests/ui-cargo/update-all-references.sh`.
 +
 +## Rustfix tests
 +
 +If the lint you are working on is making use of structured suggestions, the
 +test file should include a `// run-rustfix` comment at the top. This will
 +additionally run [rustfix] for that test. Rustfix will apply the suggestions
 +from the lint to the code of the test file and compare that to the contents of
 +a `.fixed` file.
 +
 +Use `tests/ui/update-all-references.sh` to automatically generate the
 +`.fixed` file after running the tests.
 +
 +[rustfix]: https://github.com/rust-lang/rustfix
 +
 +## Edition 2018 tests
 +
 +Some features require the 2018 edition to work (e.g. `async_await`), but
 +compile-test tests run on the 2015 edition by default. To change this behavior
 +add `// edition:2018` at the top of the test file (note that it's space-sensitive).
 +
 +## Testing manually
 +
 +Manually testing against an example file can be useful if you have added some
 +`println!`s and the test suite output becomes unreadable. To try Clippy with
 +your local modifications, run `env CLIPPY_TESTS=true cargo run --bin
 +clippy-driver -- -L ./target/debug input.rs` from the working copy root.
 +
 +With tests in place, let's have a look at implementing our lint now.
 +
 +## Lint declaration
 +
 +Let's start by opening the new file created in the `clippy_lints` crate
 +at `clippy_lints/src/foo_functions.rs`. That's the crate where all the
 +lint code is. This file has already imported some initial things we will need:
 +
 +```rust
 +use rustc_lint::{EarlyLintPass, EarlyContext};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_ast::ast::*;
 +```
 +
 +The next step is to update the lint declaration. Lints are declared using the
 +[`declare_clippy_lint!`][declare_clippy_lint] macro, and we just need to update
 +the auto-generated lint declaration to have a real description, something like this:
 +
 +```rust
 +declare_clippy_lint! {
 +    /// **What it does:**
 +    ///
 +    /// **Why is this bad?**
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // example code
 +    /// ```
 +    pub FOO_FUNCTIONS,
 +    pedantic,
 +    "function named `foo`, which is not a descriptive name"
 +}
 +```
 +
 +* The section of lines prefixed with `///` constitutes the lint documentation
 +  section. This is the default documentation style and will be displayed
 +  [like this][example_lint_page].
 +* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
 +  [lint naming guidelines][lint_naming] here when naming your lint.
 +  In short, the name should state the thing that is being checked for and
 +  read well when used with `allow`/`warn`/`deny`.
 +* `pedantic` sets the lint level to `Allow`.
 +  The exact mapping can be found [here][category_level_mapping]
 +* The last part should be a text that explains what exactly is wrong with the
 +  code
 +
 +The rest of this file contains an empty implementation for our lint pass,
 +which in this case is `EarlyLintPass` and should look like this:
 +
 +```rust
 +// clippy_lints/src/foo_functions.rs
 +
 +// .. imports and lint declaration ..
 +
 +declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
 +
 +impl EarlyLintPass for FooFunctions {}
 +```
 +
 +Normally after declaring the lint, we have to run `cargo dev update_lints`,
 +which updates some files, so Clippy knows about the new lint. Since we used
 +`cargo dev new_lint ...` to generate the lint declaration, this was done
 +automatically. While `update_lints` automates most of the things, it doesn't
 +automate everything. We will have to register our lint pass manually in the
 +`register_plugins` function in `clippy_lints/src/lib.rs`:
 +
 +```rust
 +store.register_early_pass(|| box foo_functions::FooFunctions);
 +```
 +
 +[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
 +[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
 +
 +## Lint passes
 +
 +Writing a lint that only checks for the name of a function means that we only
 +have to deal with the AST and don't have to deal with the type system at all.
 +This is good, because it makes writing this particular lint less complicated.
 +
 +We have to make this decision with every new Clippy lint. It boils down to using
 +either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
 +
 +In short, the `LateLintPass` has access to type information while the
 +`EarlyLintPass` doesn't. If you don't need access to type information, use the
 +`EarlyLintPass`. The `EarlyLintPass` is also faster. However linting speed
 +hasn't really been a concern with Clippy so far.
 +
 +Since we don't need type information for checking the function name, we used
 +`--pass=early` when running the new lint automation and all the imports were
 +added accordingly.
 +
 +[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
 +
 +## Emitting a lint
 +
 +With UI tests and the lint declaration in place, we can start working on the
 +implementation of the lint logic.
 +
 +Let's start by implementing the `EarlyLintPass` for our `FooFunctions`:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        // TODO: Emit lint here
 +    }
 +}
 +```
 +
 +We implement the [`check_fn`][check_fn] method from the
 +[`EarlyLintPass`][early_lint_pass] trait. This gives us access to various
 +information about the function that is currently being checked. More on that in
 +the next section. Let's worry about the details later and emit our lint for
 +*every* function definition first.
 +
 +Depending on how complex we want our lint message to be, we can choose from a
 +variety of lint emission functions. They can all be found in
 +[`clippy_lints/src/utils/diagnostics.rs`][diagnostics].
 +
 +`span_lint_and_help` seems most appropriate in this case. It allows us to
 +provide an extra help message and we can't really suggest a better name
 +automatically. This is how it looks:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        span_lint_and_help(
 +            cx,
 +            FOO_FUNCTIONS,
 +            span,
 +            "function named `foo`",
 +            None,
 +            "consider using a more meaningful name"
 +        );
 +    }
 +}
 +```
 +
 +Running our UI test should now produce output that contains the lint message.
 +
++According to [the rustc-dev-guide], the text should be matter of fact and avoid
++capitalization and periods, unless multiple sentences are needed.
++When code or an identifier must appear in a message or label, it should be
++surrounded with single acute accents \`.
++
 +[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
 +[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
++[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html
 +
 +## Adding the lint logic
 +
 +Writing the logic for your lint will most likely be different from our example,
 +so this section is kept rather short.
 +
 +Using the [`check_fn`][check_fn] method gives us access to [`FnKind`][fn_kind]
 +that has the [`FnKind::Fn`] variant. It provides access to the name of the
 +function/method via an [`Ident`][ident].
 +
 +With that we can expand our `check_fn` method to:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        if is_foo_fn(fn_kind) {
 +            span_lint_and_help(
 +                cx,
 +                FOO_FUNCTIONS,
 +                span,
 +                "function named `foo`",
 +                None,
 +                "consider using a more meaningful name"
 +            );
 +        }
 +    }
 +}
 +```
 +
 +We separate the lint conditional from the lint emissions because it makes the
 +code a bit easier to read. In some cases this separation would also allow to
 +write some unit tests (as opposed to only UI tests) for the separate function.
 +
 +In our example, `is_foo_fn` looks like:
 +
 +```rust
 +// use statements, impl EarlyLintPass, check_fn, ..
 +
 +fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => {
 +            // check if `fn` name is `foo`
 +            ident.name.as_str() == "foo"
 +        }
 +        // ignore closures
 +        FnKind::Closure(..) => false
 +    }
 +}
 +```
 +
 +Now we should also run the full test suite with `cargo test`. At this point
 +running `cargo test` should produce the expected output. Remember to run
 +`tests/ui/update-all-references.sh` to update the `.stderr` file.
 +
 +`cargo test` (as opposed to `cargo uitest`) will also ensure that our lint
 +implementation is not violating any Clippy lints itself.
 +
 +That should be it for the lint implementation. Running `cargo test` should now
 +pass.
 +
 +[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html
 +[`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn
 +[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
 +
 +## Author lint
 +
 +If you have trouble implementing your lint, there is also the internal `author`
 +lint to generate Clippy code that detects the offending pattern. It does not
 +work for all of the Rust syntax, but can give a good starting point.
 +
 +The quickest way to use it, is the
 +[Rust playground: play.rust-lang.org][author_example].
 +Put the code you want to lint into the editor and add the `#[clippy::author]`
 +attribute above the item. Then run Clippy via `Tools -> Clippy` and you should
 +see the generated code in the output below.
 +
 +[Here][author_example] is an example on the playground.
 +
 +If the command was executed successfully, you can copy the code over to where
 +you are implementing your lint.
 +
 +[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
 +
 +## Documentation
 +
 +The final thing before submitting our PR is to add some documentation to our
 +lint declaration.
 +
 +Please document your lint with a doc comment akin to the following:
 +
 +```rust
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for ... (describe what the lint matches).
 +    ///
 +    /// **Why is this bad?** Supply the reason for linting the code.
 +    ///
 +    /// **Known problems:** None. (Or describe where it could go wrong.)
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust,ignore
 +    /// // 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 FOO_FUNCTIONS,
 +    pedantic,
 +    "function named `foo`, which is not a descriptive name"
 +}
 +```
 +
 +Once your lint is merged, this documentation will show up in the [lint
 +list][lint_list].
 +
 +[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
 +
 +## Running rustfmt
 +
 +[Rustfmt] is a tool for formatting Rust code according to style guidelines.
 +Your code has to be formatted by `rustfmt` before a PR can be merged.
 +Clippy uses nightly `rustfmt` in the CI.
 +
 +It can be installed via `rustup`:
 +
 +```bash
 +rustup component add rustfmt --toolchain=nightly
 +```
 +
 +Use `cargo dev fmt` to format the whole codebase. Make sure that `rustfmt` is
 +installed for the nightly toolchain.
 +
 +[Rustfmt]: https://github.com/rust-lang/rustfmt
 +
 +## Debugging
 +
 +If you want to debug parts of your lint implementation, you can use the [`dbg!`]
 +macro anywhere in your code. Running the tests should then include the debug
 +output in the `stdout` part.
 +
 +[`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
 +
 +## PR Checklist
 +
 +Before submitting your PR make sure you followed all of the basic requirements:
 +
 +<!-- Sync this with `.github/PULL_REQUEST_TEMPLATE` -->
 +
 +- [ ] Followed [lint naming conventions][lint_naming]
 +- [ ] Added passing UI tests (including committed `.stderr` file)
 +- [ ] `cargo test` passes locally
 +- [ ] Executed `cargo dev update_lints`
 +- [ ] Added lint documentation
 +- [ ] Run `cargo dev fmt`
 +
 +## Cheatsheet
 +
 +Here are some pointers to things you are likely going to need for every lint:
 +
 +* [Clippy utils][utils] - Various helper functions. Maybe the function you need
 +  is already in here (`implements_trait`, `match_path`, `snippet`, etc)
 +* [Clippy diagnostics][diagnostics]
 +* [The `if_chain` macro][if_chain]
 +* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]
 +* [`Span`][span]
 +* [`Applicability`][applicability]
 +* [Common tools for writing lints](common_tools_writing_lints.md) helps with common operations
 +* [The rustc-dev-guide][rustc-dev-guide] explains a lot of internal compiler concepts
 +* [The nightly rustc docs][nightly_docs] which has been linked to throughout
 +  this guide
 +
 +For `EarlyLintPass` lints:
 +
 +* [`EarlyLintPass`][early_lint_pass]
 +* [`rustc_ast::ast`][ast]
 +
 +For `LateLintPass` lints:
 +
 +* [`LateLintPass`][late_lint_pass]
 +* [`Ty::TyKind`][ty]
 +
 +While most of Clippy's lint utils are documented, most of rustc's internals lack
 +documentation currently. This is unfortunate, but in most cases you can probably
 +get away with copying things from existing similar lints. If you are stuck,
 +don't hesitate to ask on [Discord] or in the issue/PR.
 +
 +[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
 +[if_chain]: https://docs.rs/if_chain/*/if_chain/
 +[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
 +[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
 +[span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
 +[applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
 +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
 +[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
 +[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
 +[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/index.html
 +[Discord]: https://discord.gg/rust-lang
index bbb300296be9720ab629d8426e03fef89e6c5379,0000000000000000000000000000000000000000..687fac7baa848038e9c5a735728907dd177b37fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,2724 -1,0 +1,2766 @@@
-         module: "let_and_return",
 +//! This file is managed by `cargo dev update_lints`. Do not edit.
 +
 +use lazy_static::lazy_static;
 +
 +pub mod lint;
 +pub use lint::Level;
 +pub use lint::Lint;
 +pub use lint::LINT_LEVELS;
 +
 +lazy_static! {
 +// begin lint list, do not remove this comment, it’s used in `update_lints`
 +pub static ref ALL_LINTS: Vec<Lint> = vec![
 +    Lint {
 +        name: "absurd_extreme_comparisons",
 +        group: "correctness",
 +        desc: "a comparison with a maximum or minimum value that is always true or false",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "almost_swapped",
 +        group: "correctness",
 +        desc: "`foo = bar; bar = foo` sequence",
 +        deprecation: None,
 +        module: "swap",
 +    },
 +    Lint {
 +        name: "approx_constant",
 +        group: "correctness",
 +        desc: "the approximate of a known float constant (in `std::fXX::consts`)",
 +        deprecation: None,
 +        module: "approx_const",
 +    },
 +    Lint {
 +        name: "as_conversions",
 +        group: "restriction",
 +        desc: "using a potentially dangerous silent `as` conversion",
 +        deprecation: None,
 +        module: "as_conversions",
 +    },
 +    Lint {
 +        name: "assertions_on_constants",
 +        group: "style",
 +        desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`",
 +        deprecation: None,
 +        module: "assertions_on_constants",
 +    },
 +    Lint {
 +        name: "assign_op_pattern",
 +        group: "style",
 +        desc: "assigning the result of an operation on a variable to that same variable",
 +        deprecation: None,
 +        module: "assign_ops",
 +    },
 +    Lint {
 +        name: "await_holding_lock",
 +        group: "pedantic",
 +        desc: "Inside an async function, holding a MutexGuard while calling await",
 +        deprecation: None,
 +        module: "await_holding_lock",
 +    },
 +    Lint {
 +        name: "bad_bit_mask",
 +        group: "correctness",
 +        desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`",
 +        deprecation: None,
 +        module: "bit_mask",
 +    },
 +    Lint {
 +        name: "bind_instead_of_map",
 +        group: "complexity",
 +        desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "blacklisted_name",
 +        group: "style",
 +        desc: "usage of a blacklisted/placeholder name",
 +        deprecation: None,
 +        module: "blacklisted_name",
 +    },
 +    Lint {
 +        name: "blanket_clippy_restriction_lints",
 +        group: "style",
 +        desc: "enabling the complete restriction group",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "blocks_in_if_conditions",
 +        group: "style",
 +        desc: "useless or complex blocks that can be eliminated in conditions",
 +        deprecation: None,
 +        module: "blocks_in_if_conditions",
 +    },
 +    Lint {
 +        name: "bool_comparison",
 +        group: "complexity",
 +        desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`",
 +        deprecation: None,
 +        module: "needless_bool",
 +    },
 +    Lint {
 +        name: "borrow_interior_mutable_const",
 +        group: "correctness",
 +        desc: "referencing `const` with interior mutability",
 +        deprecation: None,
 +        module: "non_copy_const",
 +    },
 +    Lint {
 +        name: "borrowed_box",
 +        group: "complexity",
 +        desc: "a borrow of a boxed type",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "box_vec",
 +        group: "perf",
 +        desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "boxed_local",
 +        group: "perf",
 +        desc: "using `Box<T>` where unnecessary",
 +        deprecation: None,
 +        module: "escape",
 +    },
 +    Lint {
 +        name: "builtin_type_shadow",
 +        group: "style",
 +        desc: "shadowing a builtin type",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "cargo_common_metadata",
 +        group: "cargo",
 +        desc: "common metadata is defined in `Cargo.toml`",
 +        deprecation: None,
 +        module: "cargo_common_metadata",
 +    },
 +    Lint {
 +        name: "cast_lossless",
 +        group: "pedantic",
 +        desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_possible_truncation",
 +        group: "pedantic",
 +        desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_possible_wrap",
 +        group: "pedantic",
 +        desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_precision_loss",
 +        group: "pedantic",
 +        desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_ptr_alignment",
 +        group: "pedantic",
 +        desc: "cast from a pointer to a more-strictly-aligned pointer",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_ref_to_mut",
 +        group: "correctness",
 +        desc: "a cast of reference to a mutable pointer",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "cast_sign_loss",
 +        group: "pedantic",
 +        desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "char_lit_as_u8",
 +        group: "complexity",
 +        desc: "casting a character literal to `u8` truncates",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "chars_last_cmp",
 +        group: "style",
 +        desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "chars_next_cmp",
 +        group: "style",
 +        desc: "using `.chars().next()` to check if a string starts with a char",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "checked_conversions",
 +        group: "pedantic",
 +        desc: "`try_from` could replace manual bounds checking when casting",
 +        deprecation: None,
 +        module: "checked_conversions",
 +    },
 +    Lint {
 +        name: "clone_double_ref",
 +        group: "correctness",
 +        desc: "using `clone` on `&&T`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "clone_on_copy",
 +        group: "complexity",
 +        desc: "using `clone` on a `Copy` type",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "clone_on_ref_ptr",
 +        group: "restriction",
 +        desc: "using \'clone\' on a ref-counted pointer",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "cmp_nan",
 +        group: "correctness",
 +        desc: "comparisons to `NAN`, which will always return false, probably not intended",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "cmp_null",
 +        group: "style",
 +        desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.",
 +        deprecation: None,
 +        module: "ptr",
 +    },
 +    Lint {
 +        name: "cmp_owned",
 +        group: "perf",
 +        desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "cognitive_complexity",
 +        group: "nursery",
 +        desc: "functions that should be split up into multiple functions",
 +        deprecation: None,
 +        module: "cognitive_complexity",
 +    },
 +    Lint {
 +        name: "collapsible_if",
 +        group: "style",
 +        desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)",
 +        deprecation: None,
 +        module: "collapsible_if",
 +    },
 +    Lint {
 +        name: "comparison_chain",
 +        group: "style",
 +        desc: "`if`s that can be rewritten with `match` and `cmp`",
 +        deprecation: None,
 +        module: "comparison_chain",
 +    },
 +    Lint {
 +        name: "copy_iterator",
 +        group: "pedantic",
 +        desc: "implementing `Iterator` on a `Copy` type",
 +        deprecation: None,
 +        module: "copy_iterator",
 +    },
 +    Lint {
 +        name: "crosspointer_transmute",
 +        group: "complexity",
 +        desc: "transmutes that have to or from types that are a pointer to the other",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "dbg_macro",
 +        group: "restriction",
 +        desc: "`dbg!` macro is intended as a debugging tool",
 +        deprecation: None,
 +        module: "dbg_macro",
 +    },
 +    Lint {
 +        name: "debug_assert_with_mut_call",
 +        group: "nursery",
 +        desc: "mutable arguments in `debug_assert{,_ne,_eq}!`",
 +        deprecation: None,
 +        module: "mutable_debug_assertion",
 +    },
 +    Lint {
 +        name: "decimal_literal_representation",
 +        group: "restriction",
 +        desc: "using decimal representation when hexadecimal would be better",
 +        deprecation: None,
 +        module: "literal_representation",
 +    },
 +    Lint {
 +        name: "declare_interior_mutable_const",
 +        group: "correctness",
 +        desc: "declaring `const` with interior mutability",
 +        deprecation: None,
 +        module: "non_copy_const",
 +    },
 +    Lint {
 +        name: "default_trait_access",
 +        group: "pedantic",
 +        desc: "checks for literal calls to `Default::default()`",
 +        deprecation: None,
 +        module: "default_trait_access",
 +    },
 +    Lint {
 +        name: "deprecated_cfg_attr",
 +        group: "complexity",
 +        desc: "usage of `cfg_attr(rustfmt)` instead of tool attributes",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "deprecated_semver",
 +        group: "correctness",
 +        desc: "use of `#[deprecated(since = \"x\")]` where x is not semver",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "deref_addrof",
 +        group: "complexity",
 +        desc: "use of `*&` or `*&mut` in an expression",
 +        deprecation: None,
 +        module: "reference",
 +    },
 +    Lint {
 +        name: "derive_hash_xor_eq",
 +        group: "correctness",
 +        desc: "deriving `Hash` but implementing `PartialEq` explicitly",
 +        deprecation: None,
 +        module: "derive",
 +    },
 +    Lint {
 +        name: "derive_ord_xor_partial_ord",
 +        group: "correctness",
 +        desc: "deriving `Ord` but implementing `PartialOrd` explicitly",
 +        deprecation: None,
 +        module: "derive",
 +    },
 +    Lint {
 +        name: "diverging_sub_expression",
 +        group: "complexity",
 +        desc: "whether an expression contains a diverging sub expression",
 +        deprecation: None,
 +        module: "eval_order_dependence",
 +    },
 +    Lint {
 +        name: "doc_markdown",
 +        group: "pedantic",
 +        desc: "presence of `_`, `::` or camel-case outside backticks in documentation",
 +        deprecation: None,
 +        module: "doc",
 +    },
 +    Lint {
 +        name: "double_comparisons",
 +        group: "complexity",
 +        desc: "unnecessary double comparisons that can be simplified",
 +        deprecation: None,
 +        module: "double_comparison",
 +    },
 +    Lint {
 +        name: "double_must_use",
 +        group: "style",
 +        desc: "`#[must_use]` attribute on a `#[must_use]`-returning function / method",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "double_neg",
 +        group: "style",
 +        desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "double_parens",
 +        group: "complexity",
 +        desc: "Warn on unnecessary double parentheses",
 +        deprecation: None,
 +        module: "double_parens",
 +    },
 +    Lint {
 +        name: "drop_bounds",
 +        group: "correctness",
 +        desc: "bounds of the form `T: Drop` are useless",
 +        deprecation: None,
 +        module: "drop_bounds",
 +    },
 +    Lint {
 +        name: "drop_copy",
 +        group: "correctness",
 +        desc: "calls to `std::mem::drop` with a value that implements Copy",
 +        deprecation: None,
 +        module: "drop_forget_ref",
 +    },
 +    Lint {
 +        name: "drop_ref",
 +        group: "correctness",
 +        desc: "calls to `std::mem::drop` with a reference instead of an owned value",
 +        deprecation: None,
 +        module: "drop_forget_ref",
 +    },
 +    Lint {
 +        name: "duplicate_underscore_argument",
 +        group: "style",
 +        desc: "function arguments having names which only differ by an underscore",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "duration_subsec",
 +        group: "complexity",
 +        desc: "checks for calculation of subsecond microseconds or milliseconds",
 +        deprecation: None,
 +        module: "duration_subsec",
 +    },
 +    Lint {
 +        name: "else_if_without_else",
 +        group: "restriction",
 +        desc: "`if` expression with an `else if`, but without a final `else` branch",
 +        deprecation: None,
 +        module: "else_if_without_else",
 +    },
 +    Lint {
 +        name: "empty_enum",
 +        group: "pedantic",
 +        desc: "enum with no variants",
 +        deprecation: None,
 +        module: "empty_enum",
 +    },
 +    Lint {
 +        name: "empty_line_after_outer_attr",
 +        group: "nursery",
 +        desc: "empty line after outer attribute",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "empty_loop",
 +        group: "style",
 +        desc: "empty `loop {}`, which should block or sleep",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "enum_clike_unportable_variant",
 +        group: "correctness",
 +        desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`",
 +        deprecation: None,
 +        module: "enum_clike",
 +    },
 +    Lint {
 +        name: "enum_glob_use",
 +        group: "pedantic",
 +        desc: "use items that import all variants of an enum",
 +        deprecation: None,
 +        module: "wildcard_imports",
 +    },
 +    Lint {
 +        name: "enum_variant_names",
 +        group: "style",
 +        desc: "enums where all variants share a prefix/postfix",
 +        deprecation: None,
 +        module: "enum_variants",
 +    },
 +    Lint {
 +        name: "eq_op",
 +        group: "correctness",
 +        desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)",
 +        deprecation: None,
 +        module: "eq_op",
 +    },
 +    Lint {
 +        name: "erasing_op",
 +        group: "correctness",
 +        desc: "using erasing operations, e.g., `x * 0` or `y & 0`",
 +        deprecation: None,
 +        module: "erasing_op",
 +    },
 +    Lint {
 +        name: "eval_order_dependence",
 +        group: "complexity",
 +        desc: "whether a variable read occurs before a write depends on sub-expression evaluation order",
 +        deprecation: None,
 +        module: "eval_order_dependence",
 +    },
 +    Lint {
 +        name: "excessive_precision",
 +        group: "style",
 +        desc: "excessive precision for float literal",
 +        deprecation: None,
 +        module: "float_literal",
 +    },
 +    Lint {
 +        name: "exit",
 +        group: "restriction",
 +        desc: "`std::process::exit` is called, terminating the program",
 +        deprecation: None,
 +        module: "exit",
 +    },
 +    Lint {
 +        name: "expect_fun_call",
 +        group: "perf",
 +        desc: "using any `expect` method with a function call",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "expect_used",
 +        group: "restriction",
 +        desc: "using `.expect()` on `Result` or `Option`, which might be better handled",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "expl_impl_clone_on_copy",
 +        group: "pedantic",
 +        desc: "implementing `Clone` explicitly on `Copy` types",
 +        deprecation: None,
 +        module: "derive",
 +    },
 +    Lint {
 +        name: "explicit_counter_loop",
 +        group: "complexity",
 +        desc: "for-looping with an explicit counter when `_.enumerate()` would do",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "explicit_deref_methods",
 +        group: "pedantic",
 +        desc: "Explicit use of deref or deref_mut method while not in a method chain.",
 +        deprecation: None,
 +        module: "dereference",
 +    },
 +    Lint {
 +        name: "explicit_into_iter_loop",
 +        group: "pedantic",
 +        desc: "for-looping over `_.into_iter()` when `_` would do",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "explicit_iter_loop",
 +        group: "pedantic",
 +        desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "explicit_write",
 +        group: "complexity",
 +        desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work",
 +        deprecation: None,
 +        module: "explicit_write",
 +    },
 +    Lint {
 +        name: "extra_unused_lifetimes",
 +        group: "complexity",
 +        desc: "unused lifetimes in function definitions",
 +        deprecation: None,
 +        module: "lifetimes",
 +    },
 +    Lint {
 +        name: "fallible_impl_from",
 +        group: "nursery",
 +        desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`",
 +        deprecation: None,
 +        module: "fallible_impl_from",
 +    },
 +    Lint {
 +        name: "filetype_is_file",
 +        group: "restriction",
 +        desc: "`FileType::is_file` is not recommended to test for readable file type",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "filter_map",
 +        group: "pedantic",
 +        desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "filter_map_next",
 +        group: "pedantic",
 +        desc: "using combination of `filter_map` and `next` which can usually be written as a single method call",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "filter_next",
 +        group: "complexity",
 +        desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "find_map",
 +        group: "pedantic",
 +        desc: "using a combination of `find` and `map` can usually be written as a single method call",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "flat_map_identity",
 +        group: "complexity",
 +        desc: "call to `flat_map` where `flatten` is sufficient",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "float_arithmetic",
 +        group: "restriction",
 +        desc: "any floating-point arithmetic statement",
 +        deprecation: None,
 +        module: "arithmetic",
 +    },
 +    Lint {
 +        name: "float_cmp",
 +        group: "correctness",
 +        desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "float_cmp_const",
 +        group: "restriction",
 +        desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon",
 +        deprecation: None,
 +        module: "misc",
 +    },
++    Lint {
++        name: "float_equality_without_abs",
++        group: "correctness",
++        desc: "float equality check without `.abs()`",
++        deprecation: None,
++        module: "float_equality_without_abs",
++    },
 +    Lint {
 +        name: "fn_address_comparisons",
 +        group: "correctness",
 +        desc: "comparison with an address of a function item",
 +        deprecation: None,
 +        module: "unnamed_address",
 +    },
 +    Lint {
 +        name: "fn_params_excessive_bools",
 +        group: "pedantic",
 +        desc: "using too many bools in function parameters",
 +        deprecation: None,
 +        module: "excessive_bools",
 +    },
 +    Lint {
 +        name: "fn_to_numeric_cast",
 +        group: "style",
 +        desc: "casting a function pointer to a numeric type other than usize",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "fn_to_numeric_cast_with_truncation",
 +        group: "style",
 +        desc: "casting a function pointer to a numeric type not wide enough to store the address",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "for_kv_map",
 +        group: "style",
 +        desc: "looping on a map using `iter` when `keys` or `values` would do",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "for_loops_over_fallibles",
 +        group: "correctness",
 +        desc: "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "forget_copy",
 +        group: "correctness",
 +        desc: "calls to `std::mem::forget` with a value that implements Copy",
 +        deprecation: None,
 +        module: "drop_forget_ref",
 +    },
 +    Lint {
 +        name: "forget_ref",
 +        group: "correctness",
 +        desc: "calls to `std::mem::forget` with a reference instead of an owned value",
 +        deprecation: None,
 +        module: "drop_forget_ref",
 +    },
 +    Lint {
 +        name: "future_not_send",
 +        group: "nursery",
 +        desc: "public Futures must be Send",
 +        deprecation: None,
 +        module: "future_not_send",
 +    },
 +    Lint {
 +        name: "get_last_with_len",
 +        group: "complexity",
 +        desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler",
 +        deprecation: None,
 +        module: "get_last_with_len",
 +    },
 +    Lint {
 +        name: "get_unwrap",
 +        group: "restriction",
 +        desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "identity_op",
 +        group: "complexity",
 +        desc: "using identity operations, e.g., `x + 0` or `y / 1`",
 +        deprecation: None,
 +        module: "identity_op",
 +    },
 +    Lint {
 +        name: "if_let_mutex",
 +        group: "correctness",
 +        desc: "locking a `Mutex` in an `if let` block can cause deadlocks",
 +        deprecation: None,
 +        module: "if_let_mutex",
 +    },
 +    Lint {
 +        name: "if_let_some_result",
 +        group: "style",
 +        desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead",
 +        deprecation: None,
 +        module: "if_let_some_result",
 +    },
 +    Lint {
 +        name: "if_not_else",
 +        group: "pedantic",
 +        desc: "`if` branches that could be swapped so no negation operation is necessary on the condition",
 +        deprecation: None,
 +        module: "if_not_else",
 +    },
 +    Lint {
 +        name: "if_same_then_else",
 +        group: "correctness",
 +        desc: "`if` with the same `then` and `else` blocks",
 +        deprecation: None,
 +        module: "copies",
 +    },
 +    Lint {
 +        name: "ifs_same_cond",
 +        group: "correctness",
 +        desc: "consecutive `if`s with the same condition",
 +        deprecation: None,
 +        module: "copies",
 +    },
 +    Lint {
 +        name: "implicit_hasher",
 +        group: "pedantic",
 +        desc: "missing generalization over different hashers",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "implicit_return",
 +        group: "restriction",
 +        desc: "use a return statement like `return expr` instead of an expression",
 +        deprecation: None,
 +        module: "implicit_return",
 +    },
 +    Lint {
 +        name: "implicit_saturating_sub",
 +        group: "pedantic",
 +        desc: "Perform saturating subtraction instead of implicitly checking lower bound of data type",
 +        deprecation: None,
 +        module: "implicit_saturating_sub",
 +    },
 +    Lint {
 +        name: "imprecise_flops",
 +        group: "nursery",
 +        desc: "usage of imprecise floating point operations",
 +        deprecation: None,
 +        module: "floating_point_arithmetic",
 +    },
 +    Lint {
 +        name: "inconsistent_digit_grouping",
 +        group: "style",
 +        desc: "integer literals with digits grouped inconsistently",
 +        deprecation: None,
 +        module: "literal_representation",
 +    },
 +    Lint {
 +        name: "indexing_slicing",
 +        group: "restriction",
 +        desc: "indexing/slicing usage",
 +        deprecation: None,
 +        module: "indexing_slicing",
 +    },
 +    Lint {
 +        name: "ineffective_bit_mask",
 +        group: "correctness",
 +        desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`",
 +        deprecation: None,
 +        module: "bit_mask",
 +    },
 +    Lint {
 +        name: "inefficient_to_string",
 +        group: "pedantic",
 +        desc: "using `to_string` on `&&T` where `T: ToString`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "infallible_destructuring_match",
 +        group: "style",
 +        desc: "a `match` statement with a single infallible arm instead of a `let`",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "infinite_iter",
 +        group: "correctness",
 +        desc: "infinite iteration",
 +        deprecation: None,
 +        module: "infinite_iter",
 +    },
 +    Lint {
 +        name: "inherent_to_string",
 +        group: "style",
 +        desc: "type implements inherent method `to_string()`, but should instead implement the `Display` trait",
 +        deprecation: None,
 +        module: "inherent_to_string",
 +    },
 +    Lint {
 +        name: "inherent_to_string_shadow_display",
 +        group: "correctness",
 +        desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait",
 +        deprecation: None,
 +        module: "inherent_to_string",
 +    },
 +    Lint {
 +        name: "inline_always",
 +        group: "pedantic",
 +        desc: "use of `#[inline(always)]`",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "inline_fn_without_body",
 +        group: "correctness",
 +        desc: "use of `#[inline]` on trait methods without bodies",
 +        deprecation: None,
 +        module: "inline_fn_without_body",
 +    },
 +    Lint {
 +        name: "int_plus_one",
 +        group: "complexity",
 +        desc: "instead of using `x >= y + 1`, use `x > y`",
 +        deprecation: None,
 +        module: "int_plus_one",
 +    },
 +    Lint {
 +        name: "integer_arithmetic",
 +        group: "restriction",
 +        desc: "any integer arithmetic expression which could overflow or panic",
 +        deprecation: None,
 +        module: "arithmetic",
 +    },
 +    Lint {
 +        name: "integer_division",
 +        group: "restriction",
 +        desc: "integer division may cause loss of precision",
 +        deprecation: None,
 +        module: "integer_division",
 +    },
 +    Lint {
 +        name: "into_iter_on_ref",
 +        group: "style",
 +        desc: "using `.into_iter()` on a reference",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "invalid_atomic_ordering",
 +        group: "correctness",
 +        desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences",
 +        deprecation: None,
 +        module: "atomic_ordering",
 +    },
 +    Lint {
 +        name: "invalid_regex",
 +        group: "correctness",
 +        desc: "invalid regular expressions",
 +        deprecation: None,
 +        module: "regex",
 +    },
 +    Lint {
 +        name: "invalid_upcast_comparisons",
 +        group: "pedantic",
 +        desc: "a comparison involving an upcast which is always true or false",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "items_after_statements",
 +        group: "pedantic",
 +        desc: "blocks where an item comes after a statement",
 +        deprecation: None,
 +        module: "items_after_statements",
 +    },
 +    Lint {
 +        name: "iter_cloned_collect",
 +        group: "style",
 +        desc: "using `.cloned().collect()` on slice to create a `Vec`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "iter_next_loop",
 +        group: "correctness",
 +        desc: "for-looping over `_.next()` which is probably not intended",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "iter_next_slice",
 +        group: "style",
 +        desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "iter_nth",
 +        group: "perf",
 +        desc: "using `.iter().nth()` on a standard library type with O(1) element access",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "iter_nth_zero",
 +        group: "style",
 +        desc: "replace `iter.nth(0)` with `iter.next()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "iter_skip_next",
 +        group: "style",
 +        desc: "using `.skip(x).next()` on an iterator",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "iterator_step_by_zero",
 +        group: "correctness",
 +        desc: "using `Iterator::step_by(0)`, which will panic at runtime",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "just_underscores_and_digits",
 +        group: "style",
 +        desc: "unclear name",
 +        deprecation: None,
 +        module: "non_expressive_names",
 +    },
 +    Lint {
 +        name: "large_const_arrays",
 +        group: "perf",
 +        desc: "large non-scalar const array may cause performance overhead",
 +        deprecation: None,
 +        module: "large_const_arrays",
 +    },
 +    Lint {
 +        name: "large_digit_groups",
 +        group: "pedantic",
 +        desc: "grouping digits into groups that are too large",
 +        deprecation: None,
 +        module: "literal_representation",
 +    },
 +    Lint {
 +        name: "large_enum_variant",
 +        group: "perf",
 +        desc: "large size difference between variants on an enum",
 +        deprecation: None,
 +        module: "large_enum_variant",
 +    },
 +    Lint {
 +        name: "large_stack_arrays",
 +        group: "pedantic",
 +        desc: "allocating large arrays on stack may cause stack overflow",
 +        deprecation: None,
 +        module: "large_stack_arrays",
 +    },
 +    Lint {
 +        name: "len_without_is_empty",
 +        group: "style",
 +        desc: "traits or impls with a public `len` method but no corresponding `is_empty` method",
 +        deprecation: None,
 +        module: "len_zero",
 +    },
 +    Lint {
 +        name: "len_zero",
 +        group: "style",
 +        desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead",
 +        deprecation: None,
 +        module: "len_zero",
 +    },
 +    Lint {
 +        name: "let_and_return",
 +        group: "style",
 +        desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block",
 +        deprecation: None,
-         module: "returns",
++        module: "returns",
 +    },
 +    Lint {
 +        name: "let_underscore_lock",
 +        group: "correctness",
 +        desc: "non-binding let on a synchronization lock",
 +        deprecation: None,
 +        module: "let_underscore",
 +    },
 +    Lint {
 +        name: "let_underscore_must_use",
 +        group: "restriction",
 +        desc: "non-binding let on a `#[must_use]` expression",
 +        deprecation: None,
 +        module: "let_underscore",
 +    },
 +    Lint {
 +        name: "let_unit_value",
 +        group: "pedantic",
 +        desc: "creating a `let` binding to a value of unit type, which usually can\'t be used afterwards",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "linkedlist",
 +        group: "pedantic",
 +        desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "logic_bug",
 +        group: "correctness",
 +        desc: "boolean expressions that contain terminals which can be eliminated",
 +        deprecation: None,
 +        module: "booleans",
 +    },
 +    Lint {
 +        name: "lossy_float_literal",
 +        group: "restriction",
 +        desc: "lossy whole number float literals",
 +        deprecation: None,
 +        module: "float_literal",
 +    },
 +    Lint {
 +        name: "macro_use_imports",
 +        group: "pedantic",
 +        desc: "#[macro_use] is no longer needed",
 +        deprecation: None,
 +        module: "macro_use",
 +    },
 +    Lint {
 +        name: "main_recursion",
 +        group: "style",
 +        desc: "recursion using the entrypoint",
 +        deprecation: None,
 +        module: "main_recursion",
 +    },
 +    Lint {
 +        name: "manual_async_fn",
 +        group: "style",
 +        desc: "manual implementations of `async` functions can be simplified using the dedicated syntax",
 +        deprecation: None,
 +        module: "manual_async_fn",
 +    },
 +    Lint {
 +        name: "manual_memcpy",
 +        group: "perf",
 +        desc: "manually copying items between slices",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "manual_non_exhaustive",
 +        group: "style",
 +        desc: "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]",
 +        deprecation: None,
 +        module: "manual_non_exhaustive",
 +    },
 +    Lint {
 +        name: "manual_saturating_arithmetic",
 +        group: "style",
 +        desc: "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "manual_swap",
 +        group: "complexity",
 +        desc: "manual swap of two variables",
 +        deprecation: None,
 +        module: "swap",
 +    },
 +    Lint {
 +        name: "many_single_char_names",
 +        group: "style",
 +        desc: "too many single character bindings",
 +        deprecation: None,
 +        module: "non_expressive_names",
 +    },
 +    Lint {
 +        name: "map_clone",
 +        group: "style",
 +        desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types",
 +        deprecation: None,
 +        module: "map_clone",
 +    },
 +    Lint {
 +        name: "map_entry",
 +        group: "perf",
 +        desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`",
 +        deprecation: None,
 +        module: "entry",
 +    },
 +    Lint {
 +        name: "map_flatten",
 +        group: "pedantic",
 +        desc: "using combinations of `flatten` and `map` which can usually be written as a single method call",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "map_identity",
 +        group: "complexity",
 +        desc: "using iterator.map(|x| x)",
 +        deprecation: None,
 +        module: "map_identity",
 +    },
 +    Lint {
 +        name: "map_unwrap_or",
 +        group: "pedantic",
 +        desc: "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)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "match_as_ref",
 +        group: "complexity",
 +        desc: "a `match` on an Option value instead of using `as_ref()` or `as_mut`",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_bool",
 +        group: "pedantic",
 +        desc: "a `match` on a boolean expression instead of an `if..else` block",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_like_matches_macro",
 +        group: "style",
 +        desc: "a match that could be written with the matches! macro",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_on_vec_items",
 +        group: "pedantic",
 +        desc: "matching on vector elements can panic",
 +        deprecation: None,
 +        module: "match_on_vec_items",
 +    },
 +    Lint {
 +        name: "match_overlapping_arm",
 +        group: "style",
 +        desc: "a `match` with overlapping arms",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_ref_pats",
 +        group: "style",
 +        desc: "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_same_arms",
 +        group: "pedantic",
 +        desc: "`match` with identical arm bodies",
 +        deprecation: None,
 +        module: "copies",
 +    },
 +    Lint {
 +        name: "match_single_binding",
 +        group: "complexity",
 +        desc: "a match with a single binding instead of using `let` statement",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_wild_err_arm",
 +        group: "pedantic",
 +        desc: "a `match` with `Err(_)` arm and take drastic actions",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "match_wildcard_for_single_variants",
 +        group: "pedantic",
 +        desc: "a wildcard enum match for a single variant",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "maybe_infinite_iter",
 +        group: "pedantic",
 +        desc: "possible infinite iteration",
 +        deprecation: None,
 +        module: "infinite_iter",
 +    },
 +    Lint {
 +        name: "mem_discriminant_non_enum",
 +        group: "correctness",
 +        desc: "calling `mem::descriminant` on non-enum type",
 +        deprecation: None,
 +        module: "mem_discriminant",
 +    },
 +    Lint {
 +        name: "mem_forget",
 +        group: "restriction",
 +        desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks",
 +        deprecation: None,
 +        module: "mem_forget",
 +    },
 +    Lint {
 +        name: "mem_replace_option_with_none",
 +        group: "style",
 +        desc: "replacing an `Option` with `None` instead of `take()`",
 +        deprecation: None,
 +        module: "mem_replace",
 +    },
 +    Lint {
 +        name: "mem_replace_with_default",
 +        group: "style",
 +        desc: "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`",
 +        deprecation: None,
 +        module: "mem_replace",
 +    },
 +    Lint {
 +        name: "mem_replace_with_uninit",
 +        group: "correctness",
 +        desc: "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`",
 +        deprecation: None,
 +        module: "mem_replace",
 +    },
 +    Lint {
 +        name: "min_max",
 +        group: "correctness",
 +        desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant",
 +        deprecation: None,
 +        module: "minmax",
 +    },
 +    Lint {
 +        name: "mismatched_target_os",
 +        group: "correctness",
 +        desc: "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "misrefactored_assign_op",
 +        group: "complexity",
 +        desc: "having a variable on both sides of an assign op",
 +        deprecation: None,
 +        module: "assign_ops",
 +    },
 +    Lint {
 +        name: "missing_const_for_fn",
 +        group: "nursery",
 +        desc: "Lint functions definitions that could be made `const fn`",
 +        deprecation: None,
 +        module: "missing_const_for_fn",
 +    },
 +    Lint {
 +        name: "missing_docs_in_private_items",
 +        group: "restriction",
 +        desc: "detects missing documentation for public and private members",
 +        deprecation: None,
 +        module: "missing_doc",
 +    },
 +    Lint {
 +        name: "missing_errors_doc",
 +        group: "pedantic",
 +        desc: "`pub fn` returns `Result` without `# Errors` in doc comment",
 +        deprecation: None,
 +        module: "doc",
 +    },
 +    Lint {
 +        name: "missing_inline_in_public_items",
 +        group: "restriction",
 +        desc: "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)",
 +        deprecation: None,
 +        module: "missing_inline",
 +    },
 +    Lint {
 +        name: "missing_safety_doc",
 +        group: "style",
 +        desc: "`pub unsafe fn` without `# Safety` docs",
 +        deprecation: None,
 +        module: "doc",
 +    },
 +    Lint {
 +        name: "mistyped_literal_suffixes",
 +        group: "correctness",
 +        desc: "mistyped literal suffix",
 +        deprecation: None,
 +        module: "literal_representation",
 +    },
 +    Lint {
 +        name: "mixed_case_hex_literals",
 +        group: "style",
 +        desc: "hex literals whose letter digits are not consistently upper- or lowercased",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "module_inception",
 +        group: "style",
 +        desc: "modules that have the same name as their parent module",
 +        deprecation: None,
 +        module: "enum_variants",
 +    },
 +    Lint {
 +        name: "module_name_repetitions",
 +        group: "pedantic",
 +        desc: "type names prefixed/postfixed with their containing module\'s name",
 +        deprecation: None,
 +        module: "enum_variants",
 +    },
 +    Lint {
 +        name: "modulo_arithmetic",
 +        group: "restriction",
 +        desc: "any modulo arithmetic statement",
 +        deprecation: None,
 +        module: "modulo_arithmetic",
 +    },
 +    Lint {
 +        name: "modulo_one",
 +        group: "correctness",
 +        desc: "taking a number modulo 1, which always returns 0",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "multiple_crate_versions",
 +        group: "cargo",
 +        desc: "multiple versions of the same crate being used",
 +        deprecation: None,
 +        module: "multiple_crate_versions",
 +    },
 +    Lint {
 +        name: "multiple_inherent_impl",
 +        group: "restriction",
 +        desc: "Multiple inherent impl that could be grouped",
 +        deprecation: None,
 +        module: "inherent_impl",
 +    },
 +    Lint {
 +        name: "must_use_candidate",
 +        group: "pedantic",
 +        desc: "function or method that could take a `#[must_use]` attribute",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "must_use_unit",
 +        group: "style",
 +        desc: "`#[must_use]` attribute on a unit-returning function / method",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "mut_from_ref",
 +        group: "correctness",
 +        desc: "fns that create mutable refs from immutable ref args",
 +        deprecation: None,
 +        module: "ptr",
 +    },
 +    Lint {
 +        name: "mut_mut",
 +        group: "pedantic",
 +        desc: "usage of double-mut refs, e.g., `&mut &mut ...`",
 +        deprecation: None,
 +        module: "mut_mut",
 +    },
 +    Lint {
 +        name: "mut_range_bound",
 +        group: "complexity",
 +        desc: "for loop over a range where one of the bounds is a mutable variable",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "mutable_key_type",
 +        group: "correctness",
 +        desc: "Check for mutable `Map`/`Set` key type",
 +        deprecation: None,
 +        module: "mut_key",
 +    },
 +    Lint {
 +        name: "mutex_atomic",
 +        group: "perf",
 +        desc: "using a mutex where an atomic value could be used instead",
 +        deprecation: None,
 +        module: "mutex_atomic",
 +    },
 +    Lint {
 +        name: "mutex_integer",
 +        group: "nursery",
 +        desc: "using a mutex for an integer type",
 +        deprecation: None,
 +        module: "mutex_atomic",
 +    },
 +    Lint {
 +        name: "naive_bytecount",
 +        group: "perf",
 +        desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values",
 +        deprecation: None,
 +        module: "bytecount",
 +    },
 +    Lint {
 +        name: "needless_arbitrary_self_type",
 +        group: "complexity",
 +        desc: "type of `self` parameter is already by default `Self`",
 +        deprecation: None,
 +        module: "needless_arbitrary_self_type",
 +    },
 +    Lint {
 +        name: "needless_bool",
 +        group: "complexity",
 +        desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`",
 +        deprecation: None,
 +        module: "needless_bool",
 +    },
 +    Lint {
 +        name: "needless_borrow",
 +        group: "nursery",
 +        desc: "taking a reference that is going to be automatically dereferenced",
 +        deprecation: None,
 +        module: "needless_borrow",
 +    },
 +    Lint {
 +        name: "needless_borrowed_reference",
 +        group: "complexity",
 +        desc: "taking a needless borrowed reference",
 +        deprecation: None,
 +        module: "needless_borrowed_ref",
 +    },
 +    Lint {
 +        name: "needless_collect",
 +        group: "perf",
 +        desc: "collecting an iterator when collect is not needed",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "needless_continue",
 +        group: "pedantic",
 +        desc: "`continue` statements that can be replaced by a rearrangement of code",
 +        deprecation: None,
 +        module: "needless_continue",
 +    },
 +    Lint {
 +        name: "needless_doctest_main",
 +        group: "style",
 +        desc: "presence of `fn main() {` in code examples",
 +        deprecation: None,
 +        module: "doc",
 +    },
 +    Lint {
 +        name: "needless_lifetimes",
 +        group: "complexity",
 +        desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them",
 +        deprecation: None,
 +        module: "lifetimes",
 +    },
 +    Lint {
 +        name: "needless_pass_by_value",
 +        group: "pedantic",
 +        desc: "functions taking arguments by value, but not consuming them in its body",
 +        deprecation: None,
 +        module: "needless_pass_by_value",
 +    },
 +    Lint {
 +        name: "needless_range_loop",
 +        group: "style",
 +        desc: "for-looping over a range of indices where an iterator over items would do",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "needless_return",
 +        group: "style",
 +        desc: "using a return statement like `return expr;` where an expression would suffice",
 +        deprecation: None,
 +        module: "returns",
 +    },
 +    Lint {
 +        name: "needless_update",
 +        group: "complexity",
 +        desc: "using `Foo { ..base }` when there are no missing fields",
 +        deprecation: None,
 +        module: "needless_update",
 +    },
 +    Lint {
 +        name: "neg_cmp_op_on_partial_ord",
 +        group: "complexity",
 +        desc: "The use of negated comparison operators on partially ordered types may produce confusing code.",
 +        deprecation: None,
 +        module: "neg_cmp_op_on_partial_ord",
 +    },
 +    Lint {
 +        name: "neg_multiply",
 +        group: "style",
 +        desc: "multiplying integers with `-1`",
 +        deprecation: None,
 +        module: "neg_multiply",
 +    },
 +    Lint {
 +        name: "never_loop",
 +        group: "correctness",
 +        desc: "any loop that will always `break` or `return`",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "new_ret_no_self",
 +        group: "style",
 +        desc: "not returning type containing `Self` in a `new` method",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "new_without_default",
 +        group: "style",
 +        desc: "`fn new() -> Self` method without `Default` implementation",
 +        deprecation: None,
 +        module: "new_without_default",
 +    },
 +    Lint {
 +        name: "no_effect",
 +        group: "complexity",
 +        desc: "statements with no effect",
 +        deprecation: None,
 +        module: "no_effect",
 +    },
 +    Lint {
 +        name: "non_ascii_literal",
 +        group: "pedantic",
 +        desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape",
 +        deprecation: None,
 +        module: "unicode",
 +    },
 +    Lint {
 +        name: "nonminimal_bool",
 +        group: "complexity",
 +        desc: "boolean expressions that can be written more concisely",
 +        deprecation: None,
 +        module: "booleans",
 +    },
 +    Lint {
 +        name: "nonsensical_open_options",
 +        group: "correctness",
 +        desc: "nonsensical combination of options for opening a file",
 +        deprecation: None,
 +        module: "open_options",
 +    },
 +    Lint {
 +        name: "not_unsafe_ptr_arg_deref",
 +        group: "correctness",
 +        desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "ok_expect",
 +        group: "style",
 +        desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "op_ref",
 +        group: "style",
 +        desc: "taking a reference to satisfy the type constraints on `==`",
 +        deprecation: None,
 +        module: "eq_op",
 +    },
 +    Lint {
 +        name: "option_as_ref_deref",
 +        group: "complexity",
 +        desc: "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "option_env_unwrap",
 +        group: "correctness",
 +        desc: "using `option_env!(...).unwrap()` to get environment variable",
 +        deprecation: None,
 +        module: "option_env_unwrap",
 +    },
 +    Lint {
 +        name: "option_if_let_else",
 +        group: "pedantic",
 +        desc: "reimplementation of Option::map_or",
 +        deprecation: None,
 +        module: "option_if_let_else",
 +    },
 +    Lint {
 +        name: "option_map_or_none",
 +        group: "style",
 +        desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "option_map_unit_fn",
 +        group: "complexity",
 +        desc: "using `option.map(f)`, where `f` is a function or closure that returns `()`",
 +        deprecation: None,
 +        module: "map_unit_fn",
 +    },
 +    Lint {
 +        name: "option_option",
 +        group: "pedantic",
 +        desc: "usage of `Option<Option<T>>`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "or_fun_call",
 +        group: "perf",
 +        desc: "using any `*or` method with a function call, which suggests `*or_else`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "out_of_bounds_indexing",
 +        group: "correctness",
 +        desc: "out of bounds constant indexing",
 +        deprecation: None,
 +        module: "indexing_slicing",
 +    },
 +    Lint {
 +        name: "overflow_check_conditional",
 +        group: "complexity",
 +        desc: "overflow checks inspired by C which are likely to panic",
 +        deprecation: None,
 +        module: "overflow_check_conditional",
 +    },
 +    Lint {
 +        name: "panic",
 +        group: "restriction",
 +        desc: "usage of the `panic!` macro",
 +        deprecation: None,
 +        module: "panic_unimplemented",
 +    },
 +    Lint {
 +        name: "panic_params",
 +        group: "style",
 +        desc: "missing parameters in `panic!` calls",
 +        deprecation: None,
 +        module: "panic_unimplemented",
 +    },
 +    Lint {
 +        name: "panicking_unwrap",
 +        group: "correctness",
 +        desc: "checks for calls of `unwrap[_err]()` that will always fail",
 +        deprecation: None,
 +        module: "unwrap",
 +    },
 +    Lint {
 +        name: "partialeq_ne_impl",
 +        group: "complexity",
 +        desc: "re-implementing `PartialEq::ne`",
 +        deprecation: None,
 +        module: "partialeq_ne_impl",
 +    },
 +    Lint {
 +        name: "path_buf_push_overwrite",
 +        group: "nursery",
 +        desc: "calling `push` with file system root on `PathBuf` can overwrite it",
 +        deprecation: None,
 +        module: "path_buf_push_overwrite",
 +    },
 +    Lint {
 +        name: "pattern_type_mismatch",
 +        group: "restriction",
 +        desc: "type of pattern does not match the expression type",
 +        deprecation: None,
 +        module: "pattern_type_mismatch",
 +    },
 +    Lint {
 +        name: "possible_missing_comma",
 +        group: "correctness",
 +        desc: "possible missing comma in array",
 +        deprecation: None,
 +        module: "formatting",
 +    },
 +    Lint {
 +        name: "precedence",
 +        group: "complexity",
 +        desc: "operations where precedence may be unclear",
 +        deprecation: None,
 +        module: "precedence",
 +    },
 +    Lint {
 +        name: "print_literal",
 +        group: "style",
 +        desc: "printing a literal with a format string",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "print_stdout",
 +        group: "restriction",
 +        desc: "printing on stdout",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "print_with_newline",
 +        group: "style",
 +        desc: "using `print!()` with a format string that ends in a single newline",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "println_empty_string",
 +        group: "style",
 +        desc: "using `println!(\"\")` with an empty string",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "ptr_arg",
 +        group: "style",
 +        desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively",
 +        deprecation: None,
 +        module: "ptr",
 +    },
 +    Lint {
 +        name: "ptr_offset_with_cast",
 +        group: "complexity",
 +        desc: "unneeded pointer offset cast",
 +        deprecation: None,
 +        module: "ptr_offset_with_cast",
 +    },
 +    Lint {
 +        name: "pub_enum_variant_names",
 +        group: "pedantic",
 +        desc: "public enums where all variants share a prefix/postfix",
 +        deprecation: None,
 +        module: "enum_variants",
 +    },
 +    Lint {
 +        name: "question_mark",
 +        group: "style",
 +        desc: "checks for expressions that could be replaced by the question mark operator",
 +        deprecation: None,
 +        module: "question_mark",
 +    },
 +    Lint {
 +        name: "range_minus_one",
 +        group: "pedantic",
 +        desc: "`x..=(y-1)` reads better as `x..y`",
 +        deprecation: None,
 +        module: "ranges",
 +    },
 +    Lint {
 +        name: "range_plus_one",
 +        group: "pedantic",
 +        desc: "`x..(y+1)` reads better as `x..=y`",
 +        deprecation: None,
 +        module: "ranges",
 +    },
 +    Lint {
 +        name: "range_zip_with_len",
 +        group: "complexity",
 +        desc: "zipping iterator with a range when `enumerate()` would do",
 +        deprecation: None,
 +        module: "ranges",
 +    },
 +    Lint {
 +        name: "redundant_allocation",
 +        group: "perf",
 +        desc: "redundant allocation",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "redundant_clone",
 +        group: "perf",
 +        desc: "`clone()` of an owned value that is going to be dropped immediately",
 +        deprecation: None,
 +        module: "redundant_clone",
 +    },
 +    Lint {
 +        name: "redundant_closure",
 +        group: "style",
 +        desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)",
 +        deprecation: None,
 +        module: "eta_reduction",
 +    },
 +    Lint {
 +        name: "redundant_closure_call",
 +        group: "complexity",
 +        desc: "throwaway closures called in the expression they are defined",
 +        deprecation: None,
 +        module: "redundant_closure_call",
 +    },
 +    Lint {
 +        name: "redundant_closure_for_method_calls",
 +        group: "pedantic",
 +        desc: "redundant closures for method calls",
 +        deprecation: None,
 +        module: "eta_reduction",
 +    },
 +    Lint {
 +        name: "redundant_field_names",
 +        group: "style",
 +        desc: "checks for fields in struct literals where shorthands could be used",
 +        deprecation: None,
 +        module: "redundant_field_names",
 +    },
 +    Lint {
 +        name: "redundant_pattern",
 +        group: "style",
 +        desc: "using `name @ _` in a pattern",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "redundant_pattern_matching",
 +        group: "style",
 +        desc: "use the proper utility function avoiding an `if let`",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "redundant_pub_crate",
 +        group: "nursery",
 +        desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.",
 +        deprecation: None,
 +        module: "redundant_pub_crate",
 +    },
 +    Lint {
 +        name: "redundant_static_lifetimes",
 +        group: "style",
 +        desc: "Using explicit `\'static` lifetime for constants or statics when elision rules would allow omitting them.",
 +        deprecation: None,
 +        module: "redundant_static_lifetimes",
 +    },
 +    Lint {
 +        name: "ref_in_deref",
 +        group: "complexity",
 +        desc: "Use of reference in auto dereference expression.",
 +        deprecation: None,
 +        module: "reference",
 +    },
 +    Lint {
 +        name: "repeat_once",
 +        group: "complexity",
 +        desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ",
 +        deprecation: None,
 +        module: "repeat_once",
 +    },
 +    Lint {
 +        name: "rest_pat_in_fully_bound_structs",
 +        group: "restriction",
 +        desc: "a match on a struct that binds all fields but still uses the wildcard pattern",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "result_map_or_into_option",
 +        group: "style",
 +        desc: "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "result_map_unit_fn",
 +        group: "complexity",
 +        desc: "using `result.map(f)`, where `f` is a function or closure that returns `()`",
 +        deprecation: None,
 +        module: "map_unit_fn",
 +    },
 +    Lint {
 +        name: "reversed_empty_ranges",
 +        group: "correctness",
 +        desc: "reversing the limits of range expressions, resulting in empty ranges",
 +        deprecation: None,
 +        module: "ranges",
 +    },
 +    Lint {
 +        name: "same_functions_in_if_condition",
 +        group: "pedantic",
 +        desc: "consecutive `if`s with the same function call",
 +        deprecation: None,
 +        module: "copies",
 +    },
 +    Lint {
 +        name: "same_item_push",
 +        group: "style",
 +        desc: "the same item is pushed inside of a for loop",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "search_is_some",
 +        group: "complexity",
 +        desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
++    Lint {
++        name: "self_assignment",
++        group: "correctness",
++        desc: "explicit self-assignment",
++        deprecation: None,
++        module: "self_assignment",
++    },
 +    Lint {
 +        name: "serde_api_misuse",
 +        group: "correctness",
 +        desc: "various things that will negatively affect your serde experience",
 +        deprecation: None,
 +        module: "serde_api",
 +    },
 +    Lint {
 +        name: "shadow_reuse",
 +        group: "restriction",
 +        desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`",
 +        deprecation: None,
 +        module: "shadow",
 +    },
 +    Lint {
 +        name: "shadow_same",
 +        group: "restriction",
 +        desc: "rebinding a name to itself, e.g., `let mut x = &mut x`",
 +        deprecation: None,
 +        module: "shadow",
 +    },
 +    Lint {
 +        name: "shadow_unrelated",
 +        group: "pedantic",
 +        desc: "rebinding a name without even using the original value",
 +        deprecation: None,
 +        module: "shadow",
 +    },
 +    Lint {
 +        name: "short_circuit_statement",
 +        group: "complexity",
 +        desc: "using a short circuit boolean condition as a statement",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "should_implement_trait",
 +        group: "style",
 +        desc: "defining a method that should be implementing a std trait",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "similar_names",
 +        group: "pedantic",
 +        desc: "similarly named items and bindings",
 +        deprecation: None,
 +        module: "non_expressive_names",
 +    },
 +    Lint {
 +        name: "single_char_pattern",
 +        group: "perf",
 +        desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`",
 +        deprecation: None,
 +        module: "methods",
 +    },
++    Lint {
++        name: "single_char_push_str",
++        group: "style",
++        desc: "`push_str()` used with a single-character string literal as parameter",
++        deprecation: None,
++        module: "methods",
++    },
 +    Lint {
 +        name: "single_component_path_imports",
 +        group: "style",
 +        desc: "imports with single component path are redundant",
 +        deprecation: None,
 +        module: "single_component_path_imports",
 +    },
 +    Lint {
 +        name: "single_match",
 +        group: "style",
 +        desc: "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "single_match_else",
 +        group: "pedantic",
 +        desc: "a `match` statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "skip_while_next",
 +        group: "complexity",
 +        desc: "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "slow_vector_initialization",
 +        group: "perf",
 +        desc: "slow vector initialization",
 +        deprecation: None,
 +        module: "slow_vector_initialization",
 +    },
 +    Lint {
 +        name: "stable_sort_primitive",
 +        group: "perf",
 +        desc: "use of sort() when sort_unstable() is equivalent",
 +        deprecation: None,
 +        module: "stable_sort_primitive",
 +    },
 +    Lint {
 +        name: "string_add",
 +        group: "restriction",
 +        desc: "using `x + ..` where x is a `String` instead of `push_str()`",
 +        deprecation: None,
 +        module: "strings",
 +    },
 +    Lint {
 +        name: "string_add_assign",
 +        group: "pedantic",
 +        desc: "using `x = x + ..` where x is a `String` instead of `push_str()`",
 +        deprecation: None,
 +        module: "strings",
 +    },
 +    Lint {
 +        name: "string_extend_chars",
 +        group: "style",
 +        desc: "using `x.extend(s.chars())` where s is a `&str` or `String`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "string_lit_as_bytes",
 +        group: "style",
 +        desc: "calling `as_bytes` on a string literal instead of using a byte string literal",
 +        deprecation: None,
 +        module: "strings",
 +    },
 +    Lint {
 +        name: "struct_excessive_bools",
 +        group: "pedantic",
 +        desc: "using too many bools in a struct",
 +        deprecation: None,
 +        module: "excessive_bools",
 +    },
 +    Lint {
 +        name: "suboptimal_flops",
 +        group: "nursery",
 +        desc: "usage of sub-optimal floating point operations",
 +        deprecation: None,
 +        module: "floating_point_arithmetic",
 +    },
 +    Lint {
 +        name: "suspicious_arithmetic_impl",
 +        group: "correctness",
 +        desc: "suspicious use of operators in impl of arithmetic trait",
 +        deprecation: None,
 +        module: "suspicious_trait_impl",
 +    },
 +    Lint {
 +        name: "suspicious_assignment_formatting",
 +        group: "style",
 +        desc: "suspicious formatting of `*=`, `-=` or `!=`",
 +        deprecation: None,
 +        module: "formatting",
 +    },
 +    Lint {
 +        name: "suspicious_else_formatting",
 +        group: "style",
 +        desc: "suspicious formatting of `else`",
 +        deprecation: None,
 +        module: "formatting",
 +    },
 +    Lint {
 +        name: "suspicious_map",
 +        group: "complexity",
 +        desc: "suspicious usage of map",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "suspicious_op_assign_impl",
 +        group: "correctness",
 +        desc: "suspicious use of operators in impl of OpAssign trait",
 +        deprecation: None,
 +        module: "suspicious_trait_impl",
 +    },
 +    Lint {
 +        name: "suspicious_unary_op_formatting",
 +        group: "style",
 +        desc: "suspicious formatting of unary `-` or `!` on the RHS of a BinOp",
 +        deprecation: None,
 +        module: "formatting",
 +    },
 +    Lint {
 +        name: "tabs_in_doc_comments",
 +        group: "style",
 +        desc: "using tabs in doc comments is not recommended",
 +        deprecation: None,
 +        module: "tabs_in_doc_comments",
 +    },
 +    Lint {
 +        name: "temporary_assignment",
 +        group: "complexity",
 +        desc: "assignments to temporaries",
 +        deprecation: None,
 +        module: "temporary_assignment",
 +    },
 +    Lint {
 +        name: "temporary_cstring_as_ptr",
 +        group: "correctness",
 +        desc: "getting the inner pointer of a temporary `CString`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "to_digit_is_some",
 +        group: "style",
 +        desc: "`char.is_digit()` is clearer",
 +        deprecation: None,
 +        module: "to_digit_is_some",
 +    },
++    Lint {
++        name: "to_string_in_display",
++        group: "correctness",
++        desc: "`to_string` method used while implementing `Display` trait",
++        deprecation: None,
++        module: "to_string_in_display",
++    },
 +    Lint {
 +        name: "todo",
 +        group: "restriction",
 +        desc: "`todo!` should not be present in production code",
 +        deprecation: None,
 +        module: "panic_unimplemented",
 +    },
 +    Lint {
 +        name: "too_many_arguments",
 +        group: "complexity",
 +        desc: "functions with too many arguments",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "too_many_lines",
 +        group: "pedantic",
 +        desc: "functions with too many lines",
 +        deprecation: None,
 +        module: "functions",
 +    },
 +    Lint {
 +        name: "toplevel_ref_arg",
 +        group: "style",
 +        desc: "an entire binding declared as `ref`, in a function argument or a `let` statement",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "trait_duplication_in_bounds",
 +        group: "pedantic",
 +        desc: "Check if the same trait bounds are specified twice during a function declaration",
 +        deprecation: None,
 +        module: "trait_bounds",
 +    },
 +    Lint {
 +        name: "transmute_bytes_to_str",
 +        group: "complexity",
 +        desc: "transmutes from a `&[u8]` to a `&str`",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_float_to_int",
 +        group: "complexity",
 +        desc: "transmutes from a float to an integer",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_int_to_bool",
 +        group: "complexity",
 +        desc: "transmutes from an integer to a `bool`",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_int_to_char",
 +        group: "complexity",
 +        desc: "transmutes from an integer to a `char`",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_int_to_float",
 +        group: "complexity",
 +        desc: "transmutes from an integer to a float",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_ptr_to_ptr",
 +        group: "complexity",
 +        desc: "transmutes from a pointer to a pointer / a reference to a reference",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmute_ptr_to_ref",
 +        group: "complexity",
 +        desc: "transmutes from a pointer to a reference type",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmutes_expressible_as_ptr_casts",
 +        group: "complexity",
 +        desc: "transmutes that could be a pointer cast",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "transmuting_null",
 +        group: "correctness",
 +        desc: "transmutes from a null pointer to a reference, which is undefined behavior",
 +        deprecation: None,
 +        module: "transmuting_null",
 +    },
 +    Lint {
 +        name: "trivial_regex",
 +        group: "style",
 +        desc: "trivial regular expressions",
 +        deprecation: None,
 +        module: "regex",
 +    },
 +    Lint {
 +        name: "trivially_copy_pass_by_ref",
 +        group: "pedantic",
 +        desc: "functions taking small copyable arguments by reference",
 +        deprecation: None,
 +        module: "trivially_copy_pass_by_ref",
 +    },
 +    Lint {
 +        name: "try_err",
 +        group: "style",
 +        desc: "return errors explicitly rather than hiding them behind a `?`",
 +        deprecation: None,
 +        module: "try_err",
 +    },
 +    Lint {
 +        name: "type_complexity",
 +        group: "complexity",
 +        desc: "usage of very complex types that might be better factored into `type` definitions",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "type_repetition_in_bounds",
 +        group: "pedantic",
 +        desc: "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`",
 +        deprecation: None,
 +        module: "trait_bounds",
 +    },
 +    Lint {
 +        name: "unicode_not_nfc",
 +        group: "pedantic",
 +        desc: "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)",
 +        deprecation: None,
 +        module: "unicode",
 +    },
 +    Lint {
 +        name: "unimplemented",
 +        group: "restriction",
 +        desc: "`unimplemented!` should not be present in production code",
 +        deprecation: None,
 +        module: "panic_unimplemented",
 +    },
 +    Lint {
 +        name: "uninit_assumed_init",
 +        group: "correctness",
 +        desc: "`MaybeUninit::uninit().assume_init()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "unit_arg",
 +        group: "complexity",
 +        desc: "passing unit to a function",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "unit_cmp",
 +        group: "correctness",
 +        desc: "comparing unit values",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "unit_return_expecting_ord",
 +        group: "correctness",
 +        desc: "fn arguments of type Fn(...) -> Ord returning the unit type ().",
 +        deprecation: None,
 +        module: "unit_return_expecting_ord",
 +    },
 +    Lint {
 +        name: "unknown_clippy_lints",
 +        group: "style",
 +        desc: "unknown_lints for scoped Clippy lints",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "unnecessary_cast",
 +        group: "complexity",
 +        desc: "cast to the same type, e.g., `x as i32` where `x: i32`",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "unnecessary_filter_map",
 +        group: "complexity",
 +        desc: "using `filter_map` when a more succinct alternative exists",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "unnecessary_fold",
 +        group: "style",
 +        desc: "using `fold` when a more succinct alternative exists",
 +        deprecation: None,
 +        module: "methods",
 +    },
++    Lint {
++        name: "unnecessary_lazy_evaluations",
++        group: "style",
++        desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation",
++        deprecation: None,
++        module: "methods",
++    },
 +    Lint {
 +        name: "unnecessary_mut_passed",
 +        group: "style",
 +        desc: "an argument passed as a mutable reference although the callee only demands an immutable reference",
 +        deprecation: None,
 +        module: "mut_reference",
 +    },
 +    Lint {
 +        name: "unnecessary_operation",
 +        group: "complexity",
 +        desc: "outer expressions with no effect",
 +        deprecation: None,
 +        module: "no_effect",
 +    },
 +    Lint {
 +        name: "unnecessary_sort_by",
 +        group: "complexity",
 +        desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer",
 +        deprecation: None,
 +        module: "unnecessary_sort_by",
 +    },
 +    Lint {
 +        name: "unnecessary_unwrap",
 +        group: "complexity",
 +        desc: "checks for calls of `unwrap[_err]()` that cannot fail",
 +        deprecation: None,
 +        module: "unwrap",
 +    },
 +    Lint {
 +        name: "unneeded_field_pattern",
 +        group: "restriction",
 +        desc: "struct fields bound to a wildcard instead of using `..`",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "unneeded_wildcard_pattern",
 +        group: "complexity",
 +        desc: "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "unnested_or_patterns",
 +        group: "pedantic",
 +        desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
 +        deprecation: None,
 +        module: "unnested_or_patterns",
 +    },
 +    Lint {
 +        name: "unreachable",
 +        group: "restriction",
 +        desc: "`unreachable!` should not be present in production code",
 +        deprecation: None,
 +        module: "panic_unimplemented",
 +    },
 +    Lint {
 +        name: "unreadable_literal",
 +        group: "pedantic",
 +        desc: "long integer literal without underscores",
 +        deprecation: None,
 +        module: "literal_representation",
 +    },
 +    Lint {
 +        name: "unsafe_derive_deserialize",
 +        group: "pedantic",
 +        desc: "deriving `serde::Deserialize` on a type that has methods using `unsafe`",
 +        deprecation: None,
 +        module: "derive",
 +    },
 +    Lint {
 +        name: "unsafe_removed_from_name",
 +        group: "style",
 +        desc: "`unsafe` removed from API names on import",
 +        deprecation: None,
 +        module: "unsafe_removed_from_name",
 +    },
 +    Lint {
 +        name: "unseparated_literal_suffix",
 +        group: "pedantic",
 +        desc: "literals whose suffix is not separated by an underscore",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "unsound_collection_transmute",
 +        group: "correctness",
 +        desc: "transmute between collections of layout-incompatible types",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "unused_io_amount",
 +        group: "correctness",
 +        desc: "unused written/read amount",
 +        deprecation: None,
 +        module: "unused_io_amount",
 +    },
 +    Lint {
 +        name: "unused_self",
 +        group: "pedantic",
 +        desc: "methods that contain a `self` argument but don\'t use it",
 +        deprecation: None,
 +        module: "unused_self",
 +    },
 +    Lint {
 +        name: "unused_unit",
 +        group: "style",
 +        desc: "needless unit expression",
 +        deprecation: None,
-         desc: "Unnecessary structure name repetition whereas `Self` is applicable",
++        module: "unused_unit",
++    },
++    Lint {
++        name: "unwrap_in_result",
++        group: "restriction",
++        desc: "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`",
++        deprecation: None,
++        module: "unwrap_in_result",
 +    },
 +    Lint {
 +        name: "unwrap_used",
 +        group: "restriction",
 +        desc: "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "use_debug",
 +        group: "restriction",
 +        desc: "use of `Debug`-based formatting",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "use_self",
 +        group: "nursery",
++        desc: "unnecessary structure name repetition whereas `Self` is applicable",
 +        deprecation: None,
 +        module: "use_self",
 +    },
 +    Lint {
 +        name: "used_underscore_binding",
 +        group: "pedantic",
 +        desc: "using a binding which is prefixed with an underscore",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "useless_asref",
 +        group: "complexity",
 +        desc: "using `as_ref` where the types before and after the call are the same",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "useless_attribute",
 +        group: "correctness",
 +        desc: "use of lint attributes on `extern crate` items",
 +        deprecation: None,
 +        module: "attrs",
 +    },
 +    Lint {
 +        name: "useless_conversion",
 +        group: "complexity",
 +        desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type",
 +        deprecation: None,
 +        module: "useless_conversion",
 +    },
 +    Lint {
 +        name: "useless_format",
 +        group: "complexity",
 +        desc: "useless use of `format!`",
 +        deprecation: None,
 +        module: "format",
 +    },
 +    Lint {
 +        name: "useless_let_if_seq",
 +        group: "nursery",
 +        desc: "unidiomatic `let mut` declaration followed by initialization in `if`",
 +        deprecation: None,
 +        module: "let_if_seq",
 +    },
 +    Lint {
 +        name: "useless_transmute",
 +        group: "nursery",
 +        desc: "transmutes that have the same to and from types or could be a cast/coercion",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "useless_vec",
 +        group: "perf",
 +        desc: "useless `vec!`",
 +        deprecation: None,
 +        module: "vec",
 +    },
 +    Lint {
 +        name: "vec_box",
 +        group: "complexity",
 +        desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap",
 +        deprecation: None,
 +        module: "types",
 +    },
 +    Lint {
 +        name: "vec_resize_to_zero",
 +        group: "correctness",
 +        desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake",
 +        deprecation: None,
 +        module: "vec_resize_to_zero",
 +    },
 +    Lint {
 +        name: "verbose_bit_mask",
 +        group: "style",
 +        desc: "expressions where a bit mask is less readable than the corresponding method call",
 +        deprecation: None,
 +        module: "bit_mask",
 +    },
 +    Lint {
 +        name: "verbose_file_reads",
 +        group: "restriction",
 +        desc: "use of `File::read_to_end` or `File::read_to_string`",
 +        deprecation: None,
 +        module: "verbose_file_reads",
 +    },
 +    Lint {
 +        name: "vtable_address_comparisons",
 +        group: "correctness",
 +        desc: "comparison with an address of a trait vtable",
 +        deprecation: None,
 +        module: "unnamed_address",
 +    },
 +    Lint {
 +        name: "while_immutable_condition",
 +        group: "correctness",
 +        desc: "variables used within while expression are not mutated in the body",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "while_let_loop",
 +        group: "complexity",
 +        desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "while_let_on_iterator",
 +        group: "style",
 +        desc: "using a while-let loop instead of a for loop on an iterator",
 +        deprecation: None,
 +        module: "loops",
 +    },
 +    Lint {
 +        name: "wildcard_dependencies",
 +        group: "cargo",
 +        desc: "wildcard dependencies being used",
 +        deprecation: None,
 +        module: "wildcard_dependencies",
 +    },
 +    Lint {
 +        name: "wildcard_enum_match_arm",
 +        group: "restriction",
 +        desc: "a wildcard enum match arm using `_`",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "wildcard_imports",
 +        group: "pedantic",
 +        desc: "lint `use _::*` statements",
 +        deprecation: None,
 +        module: "wildcard_imports",
 +    },
 +    Lint {
 +        name: "wildcard_in_or_patterns",
 +        group: "complexity",
 +        desc: "a wildcard pattern used with others patterns in same match arm",
 +        deprecation: None,
 +        module: "matches",
 +    },
 +    Lint {
 +        name: "write_literal",
 +        group: "style",
 +        desc: "writing a literal with a format string",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "write_with_newline",
 +        group: "style",
 +        desc: "using `write!()` with a format string that ends in a single newline",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "writeln_empty_string",
 +        group: "style",
 +        desc: "using `writeln!(buf, \"\")` with an empty string",
 +        deprecation: None,
 +        module: "write",
 +    },
 +    Lint {
 +        name: "wrong_pub_self_convention",
 +        group: "restriction",
 +        desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "wrong_self_convention",
 +        group: "style",
 +        desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +    Lint {
 +        name: "wrong_transmute",
 +        group: "correctness",
 +        desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless",
 +        deprecation: None,
 +        module: "transmute",
 +    },
 +    Lint {
 +        name: "zero_divided_by_zero",
 +        group: "complexity",
 +        desc: "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`",
 +        deprecation: None,
 +        module: "zero_div_zero",
 +    },
 +    Lint {
 +        name: "zero_prefixed_literal",
 +        group: "complexity",
 +        desc: "integer literals starting with `0`",
 +        deprecation: None,
 +        module: "misc_early",
 +    },
 +    Lint {
 +        name: "zero_ptr",
 +        group: "style",
 +        desc: "using `0 as *{const, mut} T`",
 +        deprecation: None,
 +        module: "misc",
 +    },
 +    Lint {
 +        name: "zero_width_space",
 +        group: "correctness",
 +        desc: "using a zero-width space in a string literal, which is confusing",
 +        deprecation: None,
 +        module: "unicode",
 +    },
 +    Lint {
 +        name: "zst_offset",
 +        group: "correctness",
 +        desc: "Check for offset calculations on raw pointers to zero-sized types",
 +        deprecation: None,
 +        module: "methods",
 +    },
 +];
 +// end lint list, do not remove this comment, it’s used in `update_lints`
 +}
index 3aff8741f6051d7e6b95e525bc1a37812b3e2173,0000000000000000000000000000000000000000..7616d8001e8853bb8e9de4e44659d01b3253bd6f
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,36 @@@
-     // Skip this test if rustup nightly is unavailable
 +use std::path::PathBuf;
 +use std::process::Command;
 +
 +#[test]
 +fn fmt() {
 +    if option_env!("RUSTC_TEST_SUITE").is_some() || option_env!("NO_FMT_TEST").is_some() {
 +        return;
 +    }
 +
-     let dev_dir = root_dir.join("clippy_dev");
-     let target_dir = root_dir.join("target");
-     let target_dir = target_dir.to_str().unwrap();
++    // Skip this test if nightly rustfmt is unavailable
 +    let rustup_output = Command::new("rustup")
 +        .args(&["component", "list", "--toolchain", "nightly"])
 +        .output()
 +        .unwrap();
 +    assert!(rustup_output.status.success());
 +    let component_output = String::from_utf8_lossy(&rustup_output.stdout);
 +    if !component_output.contains("rustfmt") {
 +        return;
 +    }
 +
 +    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-         .current_dir(dev_dir)
-         .args(&["+nightly", "run", "--target-dir", target_dir, "--", "fmt", "--check"])
 +    let output = Command::new("cargo")
++        .current_dir(root_dir)
++        .args(&["dev", "fmt", "--check"])
 +        .output()
 +        .unwrap();
 +
 +    println!("status: {}", output.status);
 +    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
 +    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
 +
 +    assert!(
 +        output.status.success(),
 +        "Formatting check failed. Run `cargo dev fmt` to update formatting."
 +    );
 +}
index 414477aedd78323ccb46ebe0eea1be00f3d7b841,0000000000000000000000000000000000000000..d75cdd625f9ec3de170ff6adae0bad84563d47e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,27 @@@
 +pub use crate::extern_exports::*;
 +
 +pub fn extern_foo() {}
 +pub fn extern_bar() {}
 +
 +pub struct ExternA;
 +
 +pub mod inner {
 +    pub mod inner_for_self_import {
 +        pub fn inner_extern_foo() {}
 +        pub fn inner_extern_bar() {}
 +    }
 +}
 +
 +mod extern_exports {
 +    pub fn extern_exported() {}
 +    pub struct ExternExportedStruct;
 +    pub enum ExternExportedEnum {
 +        A,
 +    }
 +}
++
++pub mod prelude {
++    pub mod v1 {
++        pub struct PreludeModAnywhere;
++    }
++}
index fef9f4f39f80941d56d58225a086c526bcfa9a43,0000000000000000000000000000000000000000..a414832bcd36200765be6b70ae3fe59588d64586
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,118 @@@
- use std::cell::Cell;
 +#![warn(clippy::borrow_interior_mutable_const)]
 +#![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)]
 +
 +use std::borrow::Cow;
++use std::cell::{Cell, UnsafeCell};
 +use std::fmt::Display;
 +use std::sync::atomic::{AtomicUsize, Ordering};
 +use std::sync::Once;
 +
 +const ATOMIC: AtomicUsize = AtomicUsize::new(5);
 +const CELL: Cell<usize> = Cell::new(6);
 +const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
 +const INTEGER: u8 = 8;
 +const STRING: String = String::new();
 +const STR: &str = "012345";
 +const COW: Cow<str> = Cow::Borrowed("abcdef");
 +const NO_ANN: &dyn Display = &70;
 +static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
 +const ONCE_INIT: Once = Once::new();
 +
 +trait Trait<T>: Copy {
 +    type NonCopyType;
 +
 +    const ATOMIC: AtomicUsize;
 +}
 +
 +impl Trait<u32> for u64 {
 +    type NonCopyType = u16;
 +
 +    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
 +}
 +
++// This is just a pointer that can be safely dereferended,
++// it's semantically the same as `&'static T`;
++// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
++// For more information, please see the issue #5918.
++pub struct StaticRef<T> {
++    ptr: *const T,
++}
++
++impl<T> StaticRef<T> {
++    /// Create a new `StaticRef` from a raw pointer
++    ///
++    /// ## Safety
++    ///
++    /// Callers must pass in a reference to statically allocated memory which
++    /// does not overlap with other values.
++    pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
++        StaticRef { ptr }
++    }
++}
++
++impl<T> std::ops::Deref for StaticRef<T> {
++    type Target = T;
++
++    fn deref(&self) -> &'static T {
++        unsafe { &*self.ptr }
++    }
++}
++
++// use a tuple to make sure referencing a field behind a pointer isn't linted.
++const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
++
 +fn main() {
 +    ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
 +    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
 +
 +    let _once = ONCE_INIT;
 +    let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
 +    let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
 +    let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
 +    let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
 +    let _atomic_into_inner = ATOMIC.into_inner();
 +    // these should be all fine.
 +    let _twice = (ONCE_INIT, ONCE_INIT);
 +    let _ref_twice = &(ONCE_INIT, ONCE_INIT);
 +    let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
 +    let _array_twice = [ONCE_INIT, ONCE_INIT];
 +    let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
 +    let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
 +
 +    // referencing projection is still bad.
 +    let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
 +    let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
 +    let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
 +    let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
 +    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
 +    let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability
 +    let _ = &ATOMIC_TUPLE.2;
 +    let _ = (&&&&ATOMIC_TUPLE).0;
 +    let _ = (&&&&ATOMIC_TUPLE).2;
 +    let _ = ATOMIC_TUPLE.0;
 +    let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
 +    let _ = ATOMIC_TUPLE.1.into_iter();
 +    let _ = ATOMIC_TUPLE.2;
 +    let _ = &{ ATOMIC_TUPLE };
 +
 +    CELL.set(2); //~ ERROR interior mutability
 +    assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
 +
 +    assert_eq!(INTEGER, 8);
 +    assert!(STRING.is_empty());
 +
 +    let a = ATOMIC;
 +    a.store(4, Ordering::SeqCst);
 +    assert_eq!(a.load(Ordering::SeqCst), 4);
 +
 +    STATIC_TUPLE.0.store(3, Ordering::SeqCst);
 +    assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
 +    assert!(STATIC_TUPLE.1.is_empty());
 +
 +    u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
 +    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
 +
 +    assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
++
++    let _ = &CELL_REF.0;
 +}
index dc738064a17184ddf9c1177e36d18a9db60c31b8,0000000000000000000000000000000000000000..1e0b3e4d20a5236c6b7c72162f0490bd8eb54345
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,131 @@@
-   --> $DIR/borrow_interior_mutable_const.rs:34:5
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:35:16
++  --> $DIR/borrow_interior_mutable_const.rs:65:5
 +   |
 +LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
 +   |     ^^^^^^
 +   |
 +   = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:38:22
++  --> $DIR/borrow_interior_mutable_const.rs:66:16
 +   |
 +LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
 +   |                ^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:39:25
++  --> $DIR/borrow_interior_mutable_const.rs:69:22
 +   |
 +LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
 +   |                      ^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:40:27
++  --> $DIR/borrow_interior_mutable_const.rs:70:25
 +   |
 +LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
 +   |                         ^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:41:26
++  --> $DIR/borrow_interior_mutable_const.rs:71:27
 +   |
 +LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
 +   |                           ^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:52:14
++  --> $DIR/borrow_interior_mutable_const.rs:72:26
 +   |
 +LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
 +   |                          ^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:53:14
++  --> $DIR/borrow_interior_mutable_const.rs:83:14
 +   |
 +LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
 +   |              ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:54:19
++  --> $DIR/borrow_interior_mutable_const.rs:84:14
 +   |
 +LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
 +   |              ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:55:14
++  --> $DIR/borrow_interior_mutable_const.rs:85:19
 +   |
 +LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
 +   |                   ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:56:13
++  --> $DIR/borrow_interior_mutable_const.rs:86:14
 +   |
 +LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
 +   |              ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:62:13
++  --> $DIR/borrow_interior_mutable_const.rs:87:13
 +   |
 +LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
 +   |             ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:67:5
++  --> $DIR/borrow_interior_mutable_const.rs:93:13
 +   |
 +LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
 +   |             ^^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:68:16
++  --> $DIR/borrow_interior_mutable_const.rs:98:5
 +   |
 +LL |     CELL.set(2); //~ ERROR interior mutability
 +   |     ^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:81:5
++  --> $DIR/borrow_interior_mutable_const.rs:99:16
 +   |
 +LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
 +   |                ^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
-   --> $DIR/borrow_interior_mutable_const.rs:82:16
++  --> $DIR/borrow_interior_mutable_const.rs:112:5
 +   |
 +LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
 +   |     ^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: a `const` item with interior mutability should not be borrowed
++  --> $DIR/borrow_interior_mutable_const.rs:113:16
 +   |
 +LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
 +   |                ^^^^^^^^^^^
 +   |
 +   = help: assign this const to a local or static variable, and use the variable here
 +
 +error: aborting due to 16 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5caf29c619735384ea91d3b304dcd490a12c57eb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++#![warn(clippy::repeat_once)]
++
++trait Repeat {
++    fn repeat(&self) {}
++}
++
++impl Repeat for usize {
++    fn repeat(&self) {}
++}
++
++fn main() {
++    let _ = 42.repeat();
++}
index bd8adc2c57055b20e0b515c9f24c33dbcaab902d,0000000000000000000000000000000000000000..cdbeff6a037834f818e717ddc8ae24842dc8b412
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
- error: Calling `subsec_millis()` is more concise than this calculation
++error: calling `subsec_millis()` is more concise than this calculation
 +  --> $DIR/duration_subsec.rs:10:24
 +   |
 +LL |     let bad_millis_1 = dur.subsec_micros() / 1_000;
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
 +   |
 +   = note: `-D clippy::duration-subsec` implied by `-D warnings`
 +
- error: Calling `subsec_millis()` is more concise than this calculation
++error: calling `subsec_millis()` is more concise than this calculation
 +  --> $DIR/duration_subsec.rs:11:24
 +   |
 +LL |     let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
 +
- error: Calling `subsec_micros()` is more concise than this calculation
++error: calling `subsec_micros()` is more concise than this calculation
 +  --> $DIR/duration_subsec.rs:16:22
 +   |
 +LL |     let bad_micros = dur.subsec_nanos() / 1_000;
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
 +
- error: Calling `subsec_micros()` is more concise than this calculation
++error: calling `subsec_micros()` is more concise than this calculation
 +  --> $DIR/duration_subsec.rs:21:13
 +   |
 +LL |     let _ = (&dur).subsec_nanos() / 1_000;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()`
 +
- error: Calling `subsec_micros()` is more concise than this calculation
++error: calling `subsec_micros()` is more concise than this calculation
 +  --> $DIR/duration_subsec.rs:25:13
 +   |
 +LL |     let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
 +
 +error: aborting due to 5 previous errors
 +
index 71f3f5e083e0d1f67739aa5055b7b0d78a363c26,0000000000000000000000000000000000000000..5935eea5e036e74845b71e7020526cd1d4426195
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:8:5
 +   |
 +LL |     X = 0x1_0000_0000,
 +   |     ^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings`
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:15:5
 +   |
 +LL |     X = 0x1_0000_0000,
 +   |     ^^^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:18:5
 +   |
 +LL |     A = 0xFFFF_FFFF,
 +   |     ^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:25:5
 +   |
 +LL |     Z = 0xFFFF_FFFF,
 +   |     ^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:26:5
 +   |
 +LL |     A = 0x1_0000_0000,
 +   |     ^^^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:28:5
 +   |
 +LL |     C = (i32::MIN as isize) - 1,
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:34:5
 +   |
 +LL |     Z = 0xFFFF_FFFF,
 +   |     ^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:35:5
 +   |
 +LL |     A = 0x1_0000_0000,
 +   |     ^^^^^^^^^^^^^^^^^
 +
- error: Clike enum variant discriminant is not portable to 32-bit targets
++error: C-like enum variant discriminant is not portable to 32-bit targets
 +  --> $DIR/enum_clike_unportable_variant.rs:40:5
 +   |
 +LL |     X = <usize as Trait>::Number,
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 9 previous errors
 +
index 2835391de7f5838a7013ff98feb3357826c03df7,0000000000000000000000000000000000000000..b1d481190ff53bdfa68e41934fa668c49edb05f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,101 -1,0 +1,101 @@@
- error: Variant name ends with the enum's name
++error: variant name ends with the enum's name
 +  --> $DIR/enum_variants.rs:16:5
 +   |
 +LL |     cFoo,
 +   |     ^^^^
 +   |
 +   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 +
- error: Variant name starts with the enum's name
++error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:27:5
 +   |
 +LL |     FoodGood,
 +   |     ^^^^^^^^
 +
- error: Variant name starts with the enum's name
++error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:28:5
 +   |
 +LL |     FoodMiddle,
 +   |     ^^^^^^^^^^
 +
- error: Variant name starts with the enum's name
++error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:29:5
 +   |
 +LL |     FoodBad,
 +   |     ^^^^^^^
 +
- error: All variants have the same prefix: `Food`
++error: all variants have the same prefix: `Food`
 +  --> $DIR/enum_variants.rs:26: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`
++error: all variants have the same prefix: `CallType`
 +  --> $DIR/enum_variants.rs:36: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`
++error: all variants have the same prefix: `Constant`
 +  --> $DIR/enum_variants.rs:48: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
 +
- error: All variants have the same prefix: `With`
++error: all variants have the same prefix: `With`
 +  --> $DIR/enum_variants.rs:82:1
 +   |
 +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 prefix: `Prefix`
++error: all variants have the same prefix: `Prefix`
 +  --> $DIR/enum_variants.rs:88:1
 +   |
 +LL | / enum NonCaps {
 +LL | |     Prefix的,
 +LL | |     PrefixTea,
 +LL | |     PrefixCake,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
- error: All variants have the same prefix: `With`
++error: all variants have the same prefix: `With`
 +  --> $DIR/enum_variants.rs:94:1
 +   |
 +LL | / pub enum PubSeall {
 +LL | |     WithOutCake,
 +LL | |     WithOutTea,
 +LL | |     WithOut,
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: aborting due to 10 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d40fa00c315518f891cd3165604c1ae8b8f62862
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++#![warn(clippy::float_equality_without_abs)]
++
++pub fn is_roughly_equal(a: f32, b: f32) -> bool {
++    (a - b) < f32::EPSILON
++}
++
++pub fn main() {
++    // all errors
++    is_roughly_equal(1.0, 2.0);
++    let a = 0.05;
++    let b = 0.0500001;
++
++    let _ = (a - b) < f32::EPSILON;
++    let _ = a - b < f32::EPSILON;
++    let _ = a - b.abs() < f32::EPSILON;
++    let _ = (a as f64 - b as f64) < f64::EPSILON;
++    let _ = 1.0 - 2.0 < f32::EPSILON;
++
++    let _ = f32::EPSILON > (a - b);
++    let _ = f32::EPSILON > a - b;
++    let _ = f32::EPSILON > a - b.abs();
++    let _ = f64::EPSILON > (a as f64 - b as f64);
++    let _ = f32::EPSILON > 1.0 - 2.0;
++
++    // those are correct
++    let _ = (a - b).abs() < f32::EPSILON;
++    let _ = (a as f64 - b as f64).abs() < f64::EPSILON;
++
++    let _ = f32::EPSILON > (a - b).abs();
++    let _ = f64::EPSILON > (a as f64 - b as f64).abs();
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b34c8159da04db8c2258f29d1214418d166e9676
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,92 @@@
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:4:5
++   |
++LL |     (a - b) < f32::EPSILON
++   |     -------^^^^^^^^^^^^^^^
++   |     |
++   |     help: add `.abs()`: `(a - b).abs()`
++   |
++   = note: `-D clippy::float-equality-without-abs` implied by `-D warnings`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:13:13
++   |
++LL |     let _ = (a - b) < f32::EPSILON;
++   |             -------^^^^^^^^^^^^^^^
++   |             |
++   |             help: add `.abs()`: `(a - b).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:14:13
++   |
++LL |     let _ = a - b < f32::EPSILON;
++   |             -----^^^^^^^^^^^^^^^
++   |             |
++   |             help: add `.abs()`: `(a - b).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:15:13
++   |
++LL |     let _ = a - b.abs() < f32::EPSILON;
++   |             -----------^^^^^^^^^^^^^^^
++   |             |
++   |             help: add `.abs()`: `(a - b.abs()).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:16:13
++   |
++LL |     let _ = (a as f64 - b as f64) < f64::EPSILON;
++   |             ---------------------^^^^^^^^^^^^^^^
++   |             |
++   |             help: add `.abs()`: `(a as f64 - b as f64).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:17:13
++   |
++LL |     let _ = 1.0 - 2.0 < f32::EPSILON;
++   |             ---------^^^^^^^^^^^^^^^
++   |             |
++   |             help: add `.abs()`: `(1.0 - 2.0).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:19:13
++   |
++LL |     let _ = f32::EPSILON > (a - b);
++   |             ^^^^^^^^^^^^^^^-------
++   |                            |
++   |                            help: add `.abs()`: `(a - b).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:20:13
++   |
++LL |     let _ = f32::EPSILON > a - b;
++   |             ^^^^^^^^^^^^^^^-----
++   |                            |
++   |                            help: add `.abs()`: `(a - b).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:21:13
++   |
++LL |     let _ = f32::EPSILON > a - b.abs();
++   |             ^^^^^^^^^^^^^^^-----------
++   |                            |
++   |                            help: add `.abs()`: `(a - b.abs()).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:22:13
++   |
++LL |     let _ = f64::EPSILON > (a as f64 - b as f64);
++   |             ^^^^^^^^^^^^^^^---------------------
++   |                            |
++   |                            help: add `.abs()`: `(a as f64 - b as f64).abs()`
++
++error: float equality check without `.abs()`
++  --> $DIR/float_equality_without_abs.rs:23:13
++   |
++LL |     let _ = f32::EPSILON > 1.0 - 2.0;
++   |             ^^^^^^^^^^^^^^^---------
++   |                            |
++   |                            help: add `.abs()`: `(1.0 - 2.0).abs()`
++
++error: aborting due to 11 previous errors
++
index 334ccb0101678c6c05cbb0c7418c75c8a17489b2,0000000000000000000000000000000000000000..6afee0f36b9da21b592e78b947cdc07140b14015
mode 100644,000000..100644
--- /dev/null
@@@ -1,25 -1,0 +1,25 @@@
- error: Matching on `Some` with `ok()` is redundant
++error: matching on `Some` with `ok()` is redundant
 +  --> $DIR/if_let_some_result.rs:6:5
 +   |
 +LL |     if let Some(y) = x.parse().ok() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::if-let-some-result` implied by `-D warnings`
- help: Consider matching on `Ok(y)` and removing the call to `ok` instead
++help: consider matching on `Ok(y)` and removing the call to `ok` instead
 +   |
 +LL |     if let Ok(y) = x.parse() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: Matching on `Some` with `ok()` is redundant
++error: matching on `Some` with `ok()` is redundant
 +  --> $DIR/if_let_some_result.rs:24:9
 +   |
 +LL |         if let Some(y) = x   .   parse()   .   ok   ()    {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
- help: Consider matching on `Ok(y)` and removing the call to `ok` instead
++help: consider matching on `Ok(y)` and removing the call to `ok` instead
 +   |
 +LL |         if let Ok(y) = x   .   parse()       {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 2 previous errors
 +
index 78bc4d4bd20a30359e686ac4e891dec16c2108bf,0000000000000000000000000000000000000000..53d1b86d02a962a639631ea29c6415573cb8ee51
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,27 @@@
- error: Unnecessary boolean `not` operation
++error: unnecessary boolean `not` operation
 +  --> $DIR/if_not_else.rs:9:5
 +   |
 +LL | /     if !bla() {
 +LL | |         println!("Bugs");
 +LL | |     } else {
 +LL | |         println!("Bunny");
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::if-not-else` implied by `-D warnings`
 +   = help: remove the `!` and swap the blocks of the `if`/`else`
 +
- error: Unnecessary `!=` operation
++error: unnecessary `!=` operation
 +  --> $DIR/if_not_else.rs:14:5
 +   |
 +LL | /     if 4 != 5 {
 +LL | |         println!("Bugs");
 +LL | |     } else {
 +LL | |         println!("Bunny");
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: change to `==` and swap the blocks of the `if`/`else`
 +
 +error: aborting due to 2 previous errors
 +
index 585d32845d290af4f8e66a3b1fd9a41b13332f5a,0000000000000000000000000000000000000000..aab688cc2d8b2b87d77ca9eb864a699a191edc3c
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,35 @@@
- error: Multiple implementations of this structure
++error: multiple implementations of this structure
 +  --> $DIR/impl.rs:10:1
 +   |
 +LL | / impl MyStruct {
 +LL | |     fn second() {}
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
- note: First implementation here
++note: first implementation here
 +  --> $DIR/impl.rs:6:1
 +   |
 +LL | / impl MyStruct {
 +LL | |     fn first() {}
 +LL | | }
 +   | |_^
 +
- error: Multiple implementations of this structure
++error: multiple implementations of this structure
 +  --> $DIR/impl.rs:24:5
 +   |
 +LL | /     impl super::MyStruct {
 +LL | |         fn third() {}
 +LL | |     }
 +   | |_____^
 +   |
- note: First implementation here
++note: first implementation here
 +  --> $DIR/impl.rs:6:1
 +   |
 +LL | / impl MyStruct {
 +LL | |     fn first() {}
 +LL | | }
 +   | |_^
 +
 +error: aborting due to 2 previous errors
 +
index 2eb2023b3b9ef44bbdfa0c0c7f23169f6b0de117,0000000000000000000000000000000000000000..5bb9a606422a13fdb740663f33850c3d3181f34b
mode 100644,000000..100644
--- /dev/null
@@@ -1,188 -1,0 +1,188 @@@
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:13:5
 +   |
 +LL | /     if u_8 > 0 {
 +LL | |         u_8 = u_8 - 1;
 +LL | |     }
 +   | |_____^ help: try: `u_8 = u_8.saturating_sub(1);`
 +   |
 +   = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:20:13
 +   |
 +LL | /             if u_8 > 0 {
 +LL | |                 u_8 -= 1;
 +LL | |             }
 +   | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:34:5
 +   |
 +LL | /     if u_16 > 0 {
 +LL | |         u_16 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_16 = u_16.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:44:5
 +   |
 +LL | /     if u_32 != 0 {
 +LL | |         u_32 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_32 = u_32.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:65:5
 +   |
 +LL | /     if u_64 > 0 {
 +LL | |         u_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:70:5
 +   |
 +LL | /     if 0 < u_64 {
 +LL | |         u_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:75:5
 +   |
 +LL | /     if 0 != u_64 {
 +LL | |         u_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:96:5
 +   |
 +LL | /     if u_usize > 0 {
 +LL | |         u_usize -= 1;
 +LL | |     }
 +   | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:108:5
 +   |
 +LL | /     if i_8 > i8::MIN {
 +LL | |         i_8 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:113:5
 +   |
 +LL | /     if i_8 > i8::MIN {
 +LL | |         i_8 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:118:5
 +   |
 +LL | /     if i_8 != i8::MIN {
 +LL | |         i_8 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:123:5
 +   |
 +LL | /     if i_8 != i8::MIN {
 +LL | |         i_8 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:133:5
 +   |
 +LL | /     if i_16 > i16::MIN {
 +LL | |         i_16 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:138:5
 +   |
 +LL | /     if i_16 > i16::MIN {
 +LL | |         i_16 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:143:5
 +   |
 +LL | /     if i_16 != i16::MIN {
 +LL | |         i_16 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:148:5
 +   |
 +LL | /     if i_16 != i16::MIN {
 +LL | |         i_16 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:158:5
 +   |
 +LL | /     if i_32 > i32::MIN {
 +LL | |         i_32 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:163:5
 +   |
 +LL | /     if i_32 > i32::MIN {
 +LL | |         i_32 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:168:5
 +   |
 +LL | /     if i_32 != i32::MIN {
 +LL | |         i_32 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:173:5
 +   |
 +LL | /     if i_32 != i32::MIN {
 +LL | |         i_32 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:183:5
 +   |
 +LL | /     if i64::MIN < i_64 {
 +LL | |         i_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:188:5
 +   |
 +LL | /     if i64::MIN != i_64 {
 +LL | |         i_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 +
- error: Implicitly performing saturating subtraction
++error: implicitly performing saturating subtraction
 +  --> $DIR/implicit_saturating_sub.rs:193:5
 +   |
 +LL | /     if i64::MIN < i_64 {
 +LL | |         i_64 -= 1;
 +LL | |     }
 +   | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 +
 +error: aborting due to 23 previous errors
 +
index 29a6914761c9f92c319918bbee76403312ad2724,0000000000000000000000000000000000000000..c5b020ba8ced51bce578f1337fe5ac52c7801662
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
- error: Unnecessary `>= y + 1` or `x - 1 >=`
++error: unnecessary `>= y + 1` or `x - 1 >=`
 +  --> $DIR/int_plus_one.rs:9:13
 +   |
 +LL |     let _ = x >= y + 1;
 +   |             ^^^^^^^^^^ help: change it to: `x > y`
 +   |
 +   = note: `-D clippy::int-plus-one` implied by `-D warnings`
 +
- error: Unnecessary `>= y + 1` or `x - 1 >=`
++error: unnecessary `>= y + 1` or `x - 1 >=`
 +  --> $DIR/int_plus_one.rs:10:13
 +   |
 +LL |     let _ = y + 1 <= x;
 +   |             ^^^^^^^^^^ help: change it to: `y < x`
 +
- error: Unnecessary `>= y + 1` or `x - 1 >=`
++error: unnecessary `>= y + 1` or `x - 1 >=`
 +  --> $DIR/int_plus_one.rs:12:13
 +   |
 +LL |     let _ = x - 1 >= y;
 +   |             ^^^^^^^^^^ help: change it to: `x > y`
 +
- error: Unnecessary `>= y + 1` or `x - 1 >=`
++error: unnecessary `>= y + 1` or `x - 1 >=`
 +  --> $DIR/int_plus_one.rs:13:13
 +   |
 +LL |     let _ = y <= x - 1;
 +   |             ^^^^^^^^^^ help: change it to: `y < x`
 +
 +error: aborting due to 4 previous errors
 +
index bbf61df0cda68523debcdea9309072eeb61a73e6,0000000000000000000000000000000000000000..8c10a252ee01b427ead6cc1b2c2432a505003e49
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
- error: Using `.iter().next()` on an array
++error: using `.iter().next()` on an array
 +  --> $DIR/iter_next_slice.rs:9:5
 +   |
 +LL |     s.iter().next();
 +   |     ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)`
 +   |
 +   = note: `-D clippy::iter-next-slice` implied by `-D warnings`
 +
- error: Using `.iter().next()` on a Slice without end index.
++error: using `.iter().next()` on a Slice without end index
 +  --> $DIR/iter_next_slice.rs:12:5
 +   |
 +LL |     s[2..].iter().next();
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)`
 +
- error: Using `.iter().next()` on a Slice without end index.
++error: using `.iter().next()` on a Slice without end index
 +  --> $DIR/iter_next_slice.rs:15:5
 +   |
 +LL |     v[5..].iter().next();
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)`
 +
- error: Using `.iter().next()` on an array
++error: using `.iter().next()` on an array
 +  --> $DIR/iter_next_slice.rs:18:5
 +   |
 +LL |     v.iter().next();
 +   |     ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)`
 +
 +error: aborting due to 4 previous errors
 +
index d81676a3d9f4801d06f1884e1473c8730bd7597f,0000000000000000000000000000000000000000..1f3b8ac99b19146f766e6758d0cd799d37dc92c0
mode 100644,000000..100644
--- /dev/null
@@@ -1,151 -1,0 +1,143 @@@
- mod issue_3807 {
-     // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`.
-     // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965
-     fn no_suggestion() {
-         let _ = (0..42).len() == 0;
-     }
- }
 +// run-rustfix
 +
 +#![warn(clippy::len_zero)]
 +#![allow(dead_code, unused, clippy::len_without_is_empty)]
 +
 +pub struct One;
 +struct Wither;
 +
 +trait TraitsToo {
 +    fn len(&self) -> isize;
 +    // No error; `len` is private; see issue #1085.
 +}
 +
 +impl TraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +pub struct HasIsEmpty;
 +
 +impl HasIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct HasWrongIsEmpty;
 +
 +impl HasWrongIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self, x: u32) -> bool {
 +        false
 +    }
 +}
 +
 +pub trait WithIsEmpty {
 +    fn len(&self) -> isize;
 +    fn is_empty(&self) -> bool;
 +}
 +
 +impl WithIsEmpty for Wither {
 +    fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +fn main() {
 +    let x = [1, 2];
 +    if x.is_empty() {
 +        println!("This should not happen!");
 +    }
 +
 +    if "".is_empty() {}
 +
 +    let y = One;
 +    if y.len() == 0 {
 +        // No error; `One` does not have `.is_empty()`.
 +        println!("This should not happen either!");
 +    }
 +
 +    let z: &dyn TraitsToo = &y;
 +    if z.len() > 0 {
 +        // No error; `TraitsToo` has no `.is_empty()` method.
 +        println!("Nor should this!");
 +    }
 +
 +    let has_is_empty = HasIsEmpty;
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.len() <= 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if !has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    if 1 < has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 1 >= has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    assert!(!has_is_empty.is_empty());
 +
 +    let with_is_empty: &dyn WithIsEmpty = &Wither;
 +    if with_is_empty.is_empty() {
 +        println!("Or this!");
 +    }
 +    assert!(!with_is_empty.is_empty());
 +
 +    let has_wrong_is_empty = HasWrongIsEmpty;
 +    if has_wrong_is_empty.len() == 0 {
 +        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
 +        println!("Or this!");
 +    }
 +}
 +
 +fn test_slice(b: &[u8]) {
 +    if !b.is_empty() {}
 +}
index ecdba921a5d0fde97fa67b5a3a455d953d3cdd38,0000000000000000000000000000000000000000..dc21de0001b6c76eb2f57cdba4e7416319d5b756
mode 100644,000000..100644
--- /dev/null
@@@ -1,151 -1,0 +1,143 @@@
- mod issue_3807 {
-     // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`.
-     // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965
-     fn no_suggestion() {
-         let _ = (0..42).len() == 0;
-     }
- }
 +// run-rustfix
 +
 +#![warn(clippy::len_zero)]
 +#![allow(dead_code, unused, clippy::len_without_is_empty)]
 +
 +pub struct One;
 +struct Wither;
 +
 +trait TraitsToo {
 +    fn len(&self) -> isize;
 +    // No error; `len` is private; see issue #1085.
 +}
 +
 +impl TraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +pub struct HasIsEmpty;
 +
 +impl HasIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct HasWrongIsEmpty;
 +
 +impl HasWrongIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self, x: u32) -> bool {
 +        false
 +    }
 +}
 +
 +pub trait WithIsEmpty {
 +    fn len(&self) -> isize;
 +    fn is_empty(&self) -> bool;
 +}
 +
 +impl WithIsEmpty for Wither {
 +    fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +fn main() {
 +    let x = [1, 2];
 +    if x.len() == 0 {
 +        println!("This should not happen!");
 +    }
 +
 +    if "".len() == 0 {}
 +
 +    let y = One;
 +    if y.len() == 0 {
 +        // No error; `One` does not have `.is_empty()`.
 +        println!("This should not happen either!");
 +    }
 +
 +    let z: &dyn TraitsToo = &y;
 +    if z.len() > 0 {
 +        // No error; `TraitsToo` has no `.is_empty()` method.
 +        println!("Nor should this!");
 +    }
 +
 +    let has_is_empty = HasIsEmpty;
 +    if has_is_empty.len() == 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() != 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 0 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() < 1 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() >= 1 {
 +        println!("Or this!");
 +    }
 +    if has_is_empty.len() > 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if has_is_empty.len() <= 1 {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 0 == has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 0 != has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 0 < has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 <= has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 > has_is_empty.len() {
 +        println!("Or this!");
 +    }
 +    if 1 < has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    if 1 >= has_is_empty.len() {
 +        // No error.
 +        println!("This can happen.");
 +    }
 +    assert!(!has_is_empty.is_empty());
 +
 +    let with_is_empty: &dyn WithIsEmpty = &Wither;
 +    if with_is_empty.len() == 0 {
 +        println!("Or this!");
 +    }
 +    assert!(!with_is_empty.is_empty());
 +
 +    let has_wrong_is_empty = HasWrongIsEmpty;
 +    if has_wrong_is_empty.len() == 0 {
 +        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
 +        println!("Or this!");
 +    }
 +}
 +
 +fn test_slice(b: &[u8]) {
 +    if b.len() != 0 {}
 +}
index eee3db9b7d4b04d168958c79ea4fcef45bf30e03,0000000000000000000000000000000000000000..7978176624274ab7626f9c45be5d383daf7cde36
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,17 @@@
- #![feature(range_is_empty)]
 +// run-rustfix
 +
- #![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956
 +#![warn(clippy::len_zero)]
 +#![allow(unused)]
-     // With the feature enabled, `is_empty` should be suggested
-     fn suggestion_is_fine() {
 +
++// Now that `Range(Inclusive)::is_empty` is stable (1.47), we can always suggest this
 +mod issue_3807 {
++    fn suggestion_is_fine_range() {
 +        let _ = (0..42).is_empty();
 +    }
++
++    fn suggestion_is_fine_range_inclusive() {
++        let _ = (0_u8..=42).is_empty();
++    }
 +}
 +
 +fn main() {}
index be2e0f38fd164cbef647318ba40846f0b915acff,0000000000000000000000000000000000000000..a0eb51cc9760c462372dddaaa31819db94541efe
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,17 @@@
- #![feature(range_is_empty)]
 +// run-rustfix
 +
- #![allow(stable_features)] // TODO: https://github.com/rust-lang/rust-clippy/issues/5956
 +#![warn(clippy::len_zero)]
 +#![allow(unused)]
-     // With the feature enabled, `is_empty` should be suggested
-     fn suggestion_is_fine() {
 +
++// Now that `Range(Inclusive)::is_empty` is stable (1.47), we can always suggest this
 +mod issue_3807 {
++    fn suggestion_is_fine_range() {
 +        let _ = (0..42).len() == 0;
 +    }
++
++    fn suggestion_is_fine_range_inclusive() {
++        let _ = (0_u8..=42).len() == 0;
++    }
 +}
 +
 +fn main() {}
index acb85f7100a39bbf76d9829949864931e17973d8,0000000000000000000000000000000000000000..d0defb5a79edcb582ca4b5711ce40ee3a4af0e9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,16 @@@
-   --> $DIR/len_zero_ranges.rs:11:17
 +error: length comparison to zero
- error: aborting due to previous error
++  --> $DIR/len_zero_ranges.rs:9:17
 +   |
 +LL |         let _ = (0..42).len() == 0;
 +   |                 ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()`
 +   |
 +   = note: `-D clippy::len-zero` implied by `-D warnings`
 +
++error: length comparison to zero
++  --> $DIR/len_zero_ranges.rs:13:17
++   |
++LL |         let _ = (0_u8..=42).len() == 0;
++   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0_u8..=42).is_empty()`
++
++error: aborting due to 2 previous errors
 +
index 09614b8c1ad787d98975f9c800279a1817a7d3b3,0000000000000000000000000000000000000000..73e550b3df891864fac7c2cd2a46920efbf890f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,159 @@@
 +#![allow(unused)]
 +#![warn(clippy::let_and_return)]
 +
 +fn test() -> i32 {
 +    let _y = 0; // no warning
 +    let x = 5;
 +    x
 +}
 +
 +fn test_inner() -> i32 {
 +    if true {
 +        let x = 5;
 +        x
 +    } else {
 +        0
 +    }
 +}
 +
 +fn test_nowarn_1() -> i32 {
 +    let mut x = 5;
 +    x += 1;
 +    x
 +}
 +
 +fn test_nowarn_2() -> i32 {
 +    let x = 5;
 +    x + 1
 +}
 +
 +fn test_nowarn_3() -> (i32, i32) {
 +    // this should technically warn, but we do not compare complex patterns
 +    let (x, y) = (5, 9);
 +    (x, y)
 +}
 +
 +fn test_nowarn_4() -> i32 {
 +    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
 +    let x: i32 = 5;
 +    x
 +}
 +
 +fn test_nowarn_5(x: i16) -> u16 {
 +    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
 +    let x = x as u16;
 +    x
 +}
 +
 +// False positive example
 +trait Decode {
 +    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
 +    where
 +        Self: Sized;
 +}
 +
 +macro_rules! tuple_encode {
 +    ($($x:ident),*) => (
 +        impl<$($x: Decode),*> Decode for ($($x),*) {
 +            #[inline]
 +            #[allow(non_snake_case)]
 +            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
 +                // Shouldn't trigger lint
 +                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
 +            }
 +        }
 +    );
 +}
 +
 +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
 +
 +mod no_lint_if_stmt_borrows {
 +    mod issue_3792 {
 +        use std::io::{self, BufRead, Stdin};
 +
 +        fn read_line() -> String {
 +            let stdin = io::stdin();
 +            let line = stdin.lock().lines().next().unwrap().unwrap();
 +            line
 +        }
 +    }
 +
 +    mod issue_3324 {
 +        use std::cell::RefCell;
 +        use std::rc::{Rc, Weak};
 +
 +        fn test(value: Weak<RefCell<Bar>>) -> u32 {
 +            let value = value.upgrade().unwrap();
 +            let ret = value.borrow().baz();
 +            ret
 +        }
 +
 +        struct Bar {}
 +
 +        impl Bar {
 +            fn new() -> Self {
 +                Bar {}
 +            }
 +            fn baz(&self) -> u32 {
 +                0
 +            }
 +        }
 +
 +        fn main() {
 +            let a = Rc::new(RefCell::new(Bar::new()));
 +            let b = Rc::downgrade(&a);
 +            test(b);
 +        }
 +    }
 +
 +    mod free_function {
 +        struct Inner;
 +
 +        struct Foo<'a> {
 +            inner: &'a Inner,
 +        }
 +
 +        impl Drop for Foo<'_> {
 +            fn drop(&mut self) {}
 +        }
 +
 +        impl Foo<'_> {
 +            fn value(&self) -> i32 {
 +                42
 +            }
 +        }
 +
 +        fn some_foo(inner: &Inner) -> Foo<'_> {
 +            Foo { inner }
 +        }
 +
 +        fn test() -> i32 {
 +            let x = Inner {};
 +            let value = some_foo(&x).value();
 +            value
 +        }
 +    }
 +}
 +
++mod issue_5729 {
++    use std::sync::Arc;
++
++    trait Foo {}
++
++    trait FooStorage {
++        fn foo_cloned(&self) -> Arc<dyn Foo>;
++    }
++
++    struct FooStorageImpl<T: Foo> {
++        foo: Arc<T>,
++    }
++
++    impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
++        fn foo_cloned(&self) -> Arc<dyn Foo> {
++            let clone = Arc::clone(&self.foo);
++            clone
++        }
++    }
++}
++
 +fn main() {}
index eacf948b3927a5ee28cd67b3756941d811868764,0000000000000000000000000000000000000000..fe878e5f20601ff68d80908aaf95711f52463d9e
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,45 @@@
- error: aborting due to 2 previous errors
 +error: returning the result of a `let` binding from a block
 +  --> $DIR/let_and_return.rs:7:5
 +   |
 +LL |     let x = 5;
 +   |     ---------- unnecessary `let` binding
 +LL |     x
 +   |     ^
 +   |
 +   = note: `-D clippy::let-and-return` implied by `-D warnings`
 +help: return the expression directly
 +   |
 +LL |     
 +LL |     5
 +   |
 +
 +error: returning the result of a `let` binding from a block
 +  --> $DIR/let_and_return.rs:13:9
 +   |
 +LL |         let x = 5;
 +   |         ---------- unnecessary `let` binding
 +LL |         x
 +   |         ^
 +   |
 +help: return the expression directly
 +   |
 +LL |         
 +LL |         5
 +   |
 +
++error: returning the result of a `let` binding from a block
++  --> $DIR/let_and_return.rs:154:13
++   |
++LL |             let clone = Arc::clone(&self.foo);
++   |             ---------------------------------- unnecessary `let` binding
++LL |             clone
++   |             ^^^^^
++   |
++help: return the expression directly
++   |
++LL |             
++LL |             Arc::clone(&self.foo) as _
++   |
++
++error: aborting due to 3 previous errors
 +
index 9eec6928e8cee331d0b71086069eb322007877e1,0000000000000000000000000000000000000000..4f43cff50244449b93b23b76db601285132eab85
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
- error: You are using an explicit closure for copying elements
++error: you are using an explicit closure for copying elements
 +  --> $DIR/map_clone.rs:10:22
 +   |
 +LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
-    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
++   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
 +   |
 +   = note: `-D clippy::map-clone` implied by `-D warnings`
 +
- error: You are using an explicit closure for cloning elements
++error: you are using an explicit closure for cloning elements
 +  --> $DIR/map_clone.rs:11:26
 +   |
 +LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
-    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
++   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
 +
- error: You are using an explicit closure for copying elements
++error: you are using an explicit closure for copying elements
 +  --> $DIR/map_clone.rs:12:23
 +   |
 +LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
-    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
++   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
 +
- error: You are using an explicit closure for copying elements
++error: you are using an explicit closure for copying elements
 +  --> $DIR/map_clone.rs:14:26
 +   |
 +LL |     let _: Option<u64> = Some(&16).map(|b| *b);
-    |                          ^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&16).copied()`
++   |                          ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
 +
- error: You are using an explicit closure for copying elements
++error: you are using an explicit closure for copying elements
 +  --> $DIR/map_clone.rs:15:25
 +   |
 +LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
-    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&1).copied()`
++   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
 +
- error: You are needlessly cloning iterator elements
++error: you are needlessly cloning iterator elements
 +  --> $DIR/map_clone.rs:26:29
 +   |
 +LL |     let _ = std::env::args().map(|v| v.clone());
-    |                             ^^^^^^^^^^^^^^^^^^^ help: Remove the `map` call
++   |                             ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
 +
 +error: aborting due to 6 previous errors
 +
index 7880cf36415ff87acc8ba620ceb7712ec8038e35,0000000000000000000000000000000000000000..80dd2f744b3a1137c06f513a4329afee18f9de9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,247 -1,0 +1,185 @@@
- pub struct T;
- impl T {
-     pub fn add(self, other: T) -> T {
-         self
-     }
-     // no error, not public interface
-     pub(crate) fn drop(&mut self) {}
-     // no error, private function
-     fn neg(self) -> Self {
-         self
-     }
-     // no error, private function
-     fn eq(&self, other: T) -> bool {
-         true
-     }
-     // No error; self is a ref.
-     fn sub(&self, other: T) -> &T {
-         self
-     }
-     // No error; different number of arguments.
-     fn div(self) -> T {
-         self
-     }
-     // No error; wrong return type.
-     fn rem(self, other: T) {}
-     // Fine
-     fn into_u32(self) -> u32 {
-         0
-     }
-     fn into_u16(&self) -> u16 {
-         0
-     }
-     fn to_something(self) -> u32 {
-         0
-     }
-     fn new(self) -> Self {
-         unimplemented!();
-     }
- }
- pub struct T1;
- impl T1 {
-     // Shouldn't trigger lint as it is unsafe.
-     pub unsafe fn add(self, rhs: T1) -> T1 {
-         self
-     }
-     // Should not trigger lint since this is an async function.
-     pub async fn next(&mut self) -> Option<T1> {
-         None
-     }
- }
 +// aux-build:option_helpers.rs
 +// edition:2018
 +
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::blacklisted_name,
 +    clippy::default_trait_access,
 +    clippy::missing_docs_in_private_items,
 +    clippy::missing_safety_doc,
 +    clippy::non_ascii_literal,
 +    clippy::new_without_default,
 +    clippy::needless_pass_by_value,
++    clippy::needless_lifetimes,
 +    clippy::print_stdout,
 +    clippy::must_use_candidate,
 +    clippy::use_self,
 +    clippy::useless_format,
 +    clippy::wrong_self_convention,
 +    clippy::unused_self,
 +    unused
 +)]
 +
 +#[macro_use]
 +extern crate option_helpers;
 +
 +use std::collections::BTreeMap;
 +use std::collections::HashMap;
 +use std::collections::HashSet;
 +use std::collections::VecDeque;
 +use std::iter::FromIterator;
 +use std::ops::Mul;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +use option_helpers::IteratorFalsePositives;
 +
 +struct Lt<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    #[allow(clippy::needless_lifetimes)]
 +    pub fn new<'b>(s: &'b str) -> Lt<'b> {
 +        unimplemented!()
 +    }
 +}
 +
 +struct Lt2<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt2<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    pub fn new(s: &str) -> Lt2 {
 +        unimplemented!()
 +    }
 +}
 +
 +struct Lt3<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt3<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    pub fn new() -> Lt3<'static> {
 +        unimplemented!()
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +struct U;
 +
 +impl U {
 +    fn new() -> Self {
 +        U
 +    }
 +    // Ok because `U` is `Copy`.
 +    fn to_something(self) -> u32 {
 +        0
 +    }
 +}
 +
 +struct V<T> {
 +    _dummy: T,
 +}
 +
 +impl<T> V<T> {
 +    fn new() -> Option<V<T>> {
 +        None
 +    }
 +}
 +
 +struct AsyncNew;
 +
 +impl AsyncNew {
 +    async fn new() -> Option<Self> {
 +        None
 +    }
 +}
 +
 +struct BadNew;
 +
 +impl BadNew {
 +    fn new() -> i32 {
 +        0
 +    }
 +}
 +
++struct T;
++
 +impl Mul<T> for T {
 +    type Output = T;
 +    // No error, obviously.
 +    fn mul(self, other: T) -> T {
 +        self
 +    }
 +}
 +
 +/// Checks implementation of `FILTER_NEXT` lint.
 +#[rustfmt::skip]
 +fn filter_next() {
 +    let v = vec![3, 2, 1, 0, -1, -2, -3];
 +
 +    // Single-line case.
 +    let _ = v.iter().filter(|&x| *x < 0).next();
 +
 +    // Multi-line case.
 +    let _ = v.iter().filter(|&x| {
 +                                *x < 0
 +                            }
 +                   ).next();
 +
 +    // Check that hat we don't lint if the caller is not an `Iterator`.
 +    let foo = IteratorFalsePositives { foo: 0 };
 +    let _ = foo.filter().next();
 +}
 +
 +/// Checks implementation of `SEARCH_IS_SOME` lint.
 +#[rustfmt::skip]
 +fn search_is_some() {
 +    let v = vec![3, 2, 1, 0, -1, -2, -3];
 +    let y = &&42;
 +
 +    // Check `find().is_some()`, single-line case.
 +    let _ = v.iter().find(|&x| *x < 0).is_some();
 +    let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
 +    let _ = (0..1).find(|x| *x == 0).is_some();
 +    let _ = v.iter().find(|x| **x == 0).is_some();
 +
 +    // Check `find().is_some()`, multi-line case.
 +    let _ = v.iter().find(|&x| {
 +                              *x < 0
 +                          }
 +                   ).is_some();
 +
 +    // Check `position().is_some()`, single-line case.
 +    let _ = v.iter().position(|&x| x < 0).is_some();
 +
 +    // Check `position().is_some()`, multi-line case.
 +    let _ = v.iter().position(|&x| {
 +                                  x < 0
 +                              }
 +                   ).is_some();
 +
 +    // Check `rposition().is_some()`, single-line case.
 +    let _ = v.iter().rposition(|&x| x < 0).is_some();
 +
 +    // Check `rposition().is_some()`, multi-line case.
 +    let _ = v.iter().rposition(|&x| {
 +                                   x < 0
 +                               }
 +                   ).is_some();
 +
 +    // Check that we don't lint if the caller is not an `Iterator`.
 +    let foo = IteratorFalsePositives { foo: 0 };
 +    let _ = foo.find().is_some();
 +    let _ = foo.position().is_some();
 +    let _ = foo.rposition().is_some();
 +}
 +
 +fn main() {
 +    filter_next();
 +    search_is_some();
 +}
index 01cf487ac148e77f519563bac11d9a1da659e858,0000000000000000000000000000000000000000..2a0a43e83a653089158ed99ac5e80d4d729ad8f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,109 -1,0 +1,99 @@@
- error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
-   --> $DIR/methods.rs:39:5
-    |
- LL | /     pub fn add(self, other: T) -> T {
- LL | |         self
- LL | |     }
-    | |_____^
-    |
-    = note: `-D clippy::should-implement-trait` implied by `-D warnings`
 +error: methods called `new` usually return `Self`
-   --> $DIR/methods.rs:169:5
++  --> $DIR/methods.rs:105:5
 +   |
 +LL | /     fn new() -> i32 {
 +LL | |         0
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 +
 +error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-   --> $DIR/methods.rs:188:13
++  --> $DIR/methods.rs:126:13
 +   |
 +LL |     let _ = v.iter().filter(|&x| *x < 0).next();
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::filter-next` implied by `-D warnings`
 +   = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
 +
 +error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-   --> $DIR/methods.rs:191:13
++  --> $DIR/methods.rs:129:13
 +   |
 +LL |       let _ = v.iter().filter(|&x| {
 +   |  _____________^
 +LL | |                                 *x < 0
 +LL | |                             }
 +LL | |                    ).next();
 +   | |___________________________^
 +
 +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:208:22
++  --> $DIR/methods.rs:146:22
 +   |
 +LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
 +   |
 +   = note: `-D clippy::search-is-some` implied by `-D warnings`
 +
 +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:209:20
++  --> $DIR/methods.rs:147:20
 +   |
 +LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
 +
 +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:210:20
++  --> $DIR/methods.rs:148:20
 +   |
 +LL |     let _ = (0..1).find(|x| *x == 0).is_some();
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
 +
 +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:211:22
++  --> $DIR/methods.rs:149:22
 +   |
 +LL |     let _ = v.iter().find(|x| **x == 0).is_some();
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
 +
 +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:214:13
++  --> $DIR/methods.rs:152:13
 +   |
 +LL |       let _ = v.iter().find(|&x| {
 +   |  _____________^
 +LL | |                               *x < 0
 +LL | |                           }
 +LL | |                    ).is_some();
 +   | |______________________________^
 +
 +error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:220:22
++  --> $DIR/methods.rs:158:22
 +   |
 +LL |     let _ = v.iter().position(|&x| x < 0).is_some();
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 +
 +error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:223:13
++  --> $DIR/methods.rs:161:13
 +   |
 +LL |       let _ = v.iter().position(|&x| {
 +   |  _____________^
 +LL | |                                   x < 0
 +LL | |                               }
 +LL | |                    ).is_some();
 +   | |______________________________^
 +
 +error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:229:22
++  --> $DIR/methods.rs:167:22
 +   |
 +LL |     let _ = v.iter().rposition(|&x| x < 0).is_some();
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 +
 +error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:232:13
++  --> $DIR/methods.rs:170:13
 +   |
 +LL |       let _ = v.iter().rposition(|&x| {
 +   |  _____________^
 +LL | |                                    x < 0
 +LL | |                                }
 +LL | |                    ).is_some();
 +   | |______________________________^
 +
- error: aborting due to 13 previous errors
++error: aborting due to 12 previous errors
 +
index fa8c82ae0f34022fbc212f7ed8e60622e7bf74d5,0000000000000000000000000000000000000000..062d30b262c1be2dc62988f12e535e70972afa7b
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,22 @@@
- error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
++error: the function `takes_an_immutable_reference` doesn't need a mutable reference
 +  --> $DIR/mut_reference.rs:17:34
 +   |
 +LL |     takes_an_immutable_reference(&mut 42);
 +   |                                  ^^^^^^^
 +   |
 +   = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
 +
- error: The function/method `as_ptr` doesn't need a mutable reference
++error: the function `as_ptr` doesn't need a mutable reference
 +  --> $DIR/mut_reference.rs:19:12
 +   |
 +LL |     as_ptr(&mut 42);
 +   |            ^^^^^^^
 +
- error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
++error: the method `takes_an_immutable_reference` doesn't need a mutable reference
 +  --> $DIR/mut_reference.rs:23:44
 +   |
 +LL |     my_struct.takes_an_immutable_reference(&mut 42);
 +   |                                            ^^^^^^^
 +
 +error: aborting due to 3 previous errors
 +
index 7dac086585548431a9c8b0cbd66a6376fecd504c,0000000000000000000000000000000000000000..a3511ba708a885f808e6f4afd7d257149951c891
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,48 @@@
- error: Consider using an `AtomicBool` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:6:5
 +   |
 +LL |     Mutex::new(true);
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::mutex-atomic` implied by `-D warnings`
 +
- error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:7:5
 +   |
 +LL |     Mutex::new(5usize);
 +   |     ^^^^^^^^^^^^^^^^^^
 +
- error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:8:5
 +   |
 +LL |     Mutex::new(9isize);
 +   |     ^^^^^^^^^^^^^^^^^^
 +
- error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:10:5
 +   |
 +LL |     Mutex::new(&x as *const u32);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: Consider using an `AtomicPtr` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:11:5
 +   |
 +LL |     Mutex::new(&mut x as *mut u32);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: Consider using an `AtomicUsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:12:5
 +   |
 +LL |     Mutex::new(0u32);
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::mutex-integer` implied by `-D warnings`
 +
- error: Consider using an `AtomicIsize` instead of a `Mutex` here. If you just want the locking behavior and not the internal type, consider using `Mutex<()>`.
++error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 +  --> $DIR/mutex_atomic.rs:13:5
 +   |
 +LL |     Mutex::new(0i32);
 +   |     ^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 7 previous errors
 +
index 682d7b3c4ceb4f64b0f559f37138193ce3034da6,0000000000000000000000000000000000000000..883683e08a2aa83b4356d0a31bef4a7983cdf570
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,134 @@@
- /// This should, too.
 +/// This is a test for needless `fn main()` in doctests.
 +///
 +/// # Examples
 +///
 +/// This should lint
 +/// ```
 +/// fn main() {
 +///     unimplemented!();
 +/// }
 +/// ```
 +///
- ///
++/// With an explicit return type it should lint too
++/// ```
++/// fn main() -> () {
++///     unimplemented!();
++/// }
++/// ```
 +///
++/// This should, too.
 +/// ```rust
 +/// fn main() {
 +///     unimplemented!();
 +/// }
 +/// ```
 +///
 +/// This one too.
- /// We should not lint ignored examples:
 +/// ```no_run
 +/// fn main() {
 +///     unimplemented!();
 +/// }
 +/// ```
 +fn bad_doctests() {}
 +
 +/// # Examples
 +///
 +/// This shouldn't lint, because the `main` is empty:
 +/// ```
 +/// fn main(){}
 +/// ```
 +///
++/// This shouldn't lint either, because main is async:
++/// ```
++/// async fn main() {
++///     assert_eq!(42, ANSWER);
++/// }
++/// ```
++///
++/// Same here, because the return type is not the unit type:
++/// ```
++/// fn main() -> Result<()> {
++///     Ok(())
++/// }
++/// ```
++///
 +/// This shouldn't lint either, because there's a `static`:
 +/// ```
 +/// static ANSWER: i32 = 42;
 +///
 +/// fn main() {
 +///     assert_eq!(42, ANSWER);
 +/// }
 +/// ```
 +///
++/// This shouldn't lint either, because there's a `const`:
++/// ```
++/// fn main() {
++///     assert_eq!(42, ANSWER);
++/// }
++///
++/// const ANSWER: i32 = 42;
++/// ```
++///
 +/// Neither should this lint because of `extern crate`:
 +/// ```
 +/// #![feature(test)]
 +/// extern crate test;
 +/// fn main() {
 +///     assert_eq(1u8, test::black_box(1));
 +/// }
 +/// ```
 +///
- ///
++/// Neither should this lint because it has an extern block:
++/// ```
++/// extern {}
++/// fn main() {
++///     unimplemented!();
++/// }
++/// ```
++///
++/// This should not lint because there is another function defined:
++/// ```
++/// fn fun() {}
++///
++/// fn main() {
++///     unimplemented!();
++/// }
++/// ```
 +///
++/// We should not lint inside raw strings ...
++/// ```
++/// let string = r#"
++/// fn main() {
++///     unimplemented!();
++/// }
++/// "#;
++/// ```
++///
++/// ... or comments
++/// ```
++/// // fn main() {
++/// //     let _inception = 42;
++/// // }
++/// let _inception = 42;
++/// ```
++///
++/// We should not lint ignored examples:
 +/// ```rust,ignore
 +/// fn main() {
 +///     unimplemented!();
 +/// }
 +/// ```
 +///
 +/// Or even non-rust examples:
 +/// ```text
 +/// fn main() {
 +///     is what starts the program
 +/// }
 +/// ```
 +fn no_false_positives() {}
 +
 +fn main() {
 +    bad_doctests();
 +    no_false_positives();
 +}
index 65d40ee6832f289d0130bf1d992b3f7b9f470d05,0000000000000000000000000000000000000000..05c7f9d33a7924f3d1ea642b0ad665f7edbf06d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,28 @@@
-   --> $DIR/needless_doc_main.rs:15:4
 +error: needless `fn main` in doctest
 +  --> $DIR/needless_doc_main.rs:7:4
 +   |
 +LL | /// fn main() {
 +   |    ^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::needless-doctest-main` implied by `-D warnings`
 +
 +error: needless `fn main` in doctest
-   --> $DIR/needless_doc_main.rs:23:4
++  --> $DIR/needless_doc_main.rs:14:4
++   |
++LL | /// fn main() -> () {
++   |    ^^^^^^^^^^^^^^^^^^
++
++error: needless `fn main` in doctest
++  --> $DIR/needless_doc_main.rs:21:4
 +   |
 +LL | /// fn main() {
 +   |    ^^^^^^^^^^^^
 +
 +error: needless `fn main` in doctest
- error: aborting due to 3 previous errors
++  --> $DIR/needless_doc_main.rs:28:4
 +   |
 +LL | /// fn main() {
 +   |    ^^^^^^^^^^^^
 +
++error: aborting due to 4 previous errors
 +
index ad20e2381073aae324d7f90474f89befe77aa24b,0000000000000000000000000000000000000000..d849e093da7bb821a765122d0d966ba78adf4a39
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,95 @@@
 +// run-rustfix
 +
 +#![allow(unused, clippy::needless_bool)]
 +#![allow(clippy::if_same_then_else, clippy::single_match)]
 +#![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 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()
++    }
++}
++
 +fn main() {
 +    let _ = test_end_of_fn();
 +    let _ = test_no_semicolon();
 +    let _ = test_if_block();
 +    let _ = test_match(true);
 +    test_closure();
 +}
index af0cdfb207ff568f9e0cbc29225437196be17868,0000000000000000000000000000000000000000..29f2bd1852af00e9f1df68916f1f7624046e4c93
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,95 @@@
 +// run-rustfix
 +
 +#![allow(unused, clippy::needless_bool)]
 +#![allow(clippy::if_same_then_else, clippy::single_match)]
 +#![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 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();
++    }
++}
++
 +fn main() {
 +    let _ = test_end_of_fn();
 +    let _ = test_no_semicolon();
 +    let _ = test_if_block();
 +    let _ = test_match(true);
 +    test_closure();
 +}
index c34eecbcbb639bc906ff845e5332e790cf3364ee,0000000000000000000000000000000000000000..f73c833a801f3dc143bb92545a5e7ad41b566916
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,88 @@@
- error: aborting due to 12 previous errors
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:18: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:22:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:27:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:29:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:35:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:37:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:44:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:46:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:54:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:59:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:61:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
 +  --> $DIR/needless_return.rs:68:14
 +   |
 +LL |         _ => return,
 +   |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +
++error: unneeded `return` statement
++  --> $DIR/needless_return.rs:83:9
++   |
++LL |         return String::from("test");
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
++
++error: unneeded `return` statement
++  --> $DIR/needless_return.rs:85:9
++   |
++LL |         return String::new();
++   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
++
++error: aborting due to 14 previous errors
 +
index 2c2d1e275893fae41e3965c9c4568f2afad8c6e8,0000000000000000000000000000000000000000..e82873629a54b0de91ad1068fff7d552001fe81b
mode 100644,000000..100644
--- /dev/null
@@@ -1,212 -1,0 +1,342 @@@
- struct MutPointerReturnerOk2;
 +#![warn(clippy::new_ret_no_self)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +trait R {
 +    type Item;
 +}
 +
 +trait Q {
 +    type Item;
 +    type Item2;
 +}
 +
 +struct S;
 +
 +impl R for S {
 +    type Item = Self;
 +}
 +
 +impl S {
 +    // should not trigger the lint
 +    pub fn new() -> impl R<Item = Self> {
 +        S
 +    }
 +}
 +
 +struct S2;
 +
 +impl R for S2 {
 +    type Item = Self;
 +}
 +
 +impl S2 {
 +    // should not trigger the lint
 +    pub fn new(_: String) -> impl R<Item = Self> {
 +        S2
 +    }
 +}
 +
 +struct S3;
 +
 +impl R for S3 {
 +    type Item = u32;
 +}
 +
 +impl S3 {
 +    // should trigger the lint
 +    pub fn new(_: String) -> impl R<Item = u32> {
 +        S3
 +    }
 +}
 +
 +struct S4;
 +
 +impl Q for S4 {
 +    type Item = u32;
 +    type Item2 = Self;
 +}
 +
 +impl S4 {
 +    // should not trigger the lint
 +    pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
 +        S4
 +    }
 +}
 +
 +struct T;
 +
 +impl T {
 +    // should not trigger lint
 +    pub fn new() -> Self {
 +        unimplemented!();
 +    }
 +}
 +
 +struct U;
 +
 +impl U {
 +    // should trigger lint
 +    pub fn new() -> u32 {
 +        unimplemented!();
 +    }
 +}
 +
 +struct V;
 +
 +impl V {
 +    // should trigger lint
 +    pub fn new(_: String) -> u32 {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk;
 +
 +impl TupleReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> (Self, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk2;
 +
 +impl TupleReturnerOk2 {
 +    // should not trigger lint (it doesn't matter which element in the tuple is Self)
 +    pub fn new() -> (u32, Self) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerOk3;
 +
 +impl TupleReturnerOk3 {
 +    // should not trigger lint (tuple can contain multiple Self)
 +    pub fn new() -> (Self, Self) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct TupleReturnerBad;
 +
 +impl TupleReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> (u32, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct MutPointerReturnerOk;
 +
 +impl MutPointerReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> *mut Self {
 +        unimplemented!();
 +    }
 +}
 +
- impl MutPointerReturnerOk2 {
++struct ConstPointerReturnerOk2;
 +
++impl ConstPointerReturnerOk2 {
 +    // should not trigger lint
 +    pub fn new() -> *const Self {
 +        unimplemented!();
 +    }
 +}
 +
 +struct MutPointerReturnerBad;
 +
 +impl MutPointerReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> *mut V {
 +        unimplemented!();
 +    }
 +}
 +
 +struct GenericReturnerOk;
 +
 +impl GenericReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> Option<Self> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct GenericReturnerBad;
 +
 +impl GenericReturnerBad {
 +    // should trigger lint
 +    pub fn new() -> Option<u32> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk;
 +
 +impl NestedReturnerOk {
 +    // should not trigger lint
 +    pub fn new() -> (Option<Self>, u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk2;
 +
 +impl NestedReturnerOk2 {
 +    // should not trigger lint
 +    pub fn new() -> ((Self, u32), u32) {
 +        unimplemented!();
 +    }
 +}
 +
 +struct NestedReturnerOk3;
 +
 +impl NestedReturnerOk3 {
 +    // should not trigger lint
 +    pub fn new() -> Option<(Self, u32)> {
 +        unimplemented!();
 +    }
 +}
 +
 +struct WithLifetime<'a> {
 +    cat: &'a str,
 +}
 +
 +impl<'a> WithLifetime<'a> {
 +    // should not trigger the lint, because the lifetimes are different
 +    pub fn new<'b: 'a>(s: &'b str) -> WithLifetime<'b> {
 +        unimplemented!();
 +    }
 +}
++
++mod issue5435 {
++    struct V;
++
++    pub trait TraitRetSelf {
++        // should not trigger lint
++        fn new() -> Self;
++    }
++
++    pub trait TraitRet {
++        // should trigger lint as we are in trait definition
++        fn new() -> String;
++    }
++    pub struct StructRet;
++    impl TraitRet for StructRet {
++        // should not trigger lint as we are in the impl block
++        fn new() -> String {
++            unimplemented!();
++        }
++    }
++
++    pub trait TraitRet2 {
++        // should trigger lint
++        fn new(_: String) -> String;
++    }
++
++    trait TupleReturnerOk {
++        // should not trigger lint
++        fn new() -> (Self, u32)
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait TupleReturnerOk2 {
++        // should not trigger lint (it doesn't matter which element in the tuple is Self)
++        fn new() -> (u32, Self)
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait TupleReturnerOk3 {
++        // should not trigger lint (tuple can contain multiple Self)
++        fn new() -> (Self, Self)
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait TupleReturnerBad {
++        // should trigger lint
++        fn new() -> (u32, u32) {
++            unimplemented!();
++        }
++    }
++
++    trait MutPointerReturnerOk {
++        // should not trigger lint
++        fn new() -> *mut Self
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait ConstPointerReturnerOk2 {
++        // should not trigger lint
++        fn new() -> *const Self
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait MutPointerReturnerBad {
++        // should trigger lint
++        fn new() -> *mut V {
++            unimplemented!();
++        }
++    }
++
++    trait GenericReturnerOk {
++        // should not trigger lint
++        fn new() -> Option<Self>
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait NestedReturnerOk {
++        // should not trigger lint
++        fn new() -> (Option<Self>, u32)
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait NestedReturnerOk2 {
++        // should not trigger lint
++        fn new() -> ((Self, u32), u32)
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++
++    trait NestedReturnerOk3 {
++        // should not trigger lint
++        fn new() -> Option<(Self, u32)>
++        where
++            Self: Sized,
++        {
++            unimplemented!();
++        }
++    }
++}
index dd5a24bcbe7aed4c1ba4b792942ecac8f8cf9ea2,0000000000000000000000000000000000000000..8217bc6187f93aa5cfce1ddbc5ce7ed4788b6173
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,80 @@@
- error: aborting due to 6 previous errors
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:49:5
 +   |
 +LL | /     pub fn new(_: String) -> impl R<Item = u32> {
 +LL | |         S3
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 +
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:81:5
 +   |
 +LL | /     pub fn new() -> u32 {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:90:5
 +   |
 +LL | /     pub fn new(_: String) -> u32 {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:126:5
 +   |
 +LL | /     pub fn new() -> (u32, u32) {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:153:5
 +   |
 +LL | /     pub fn new() -> *mut V {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: methods called `new` usually return `Self`
 +  --> $DIR/new_ret_no_self.rs:171:5
 +   |
 +LL | /     pub fn new() -> Option<u32> {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:224:9
++   |
++LL |         fn new() -> String;
++   |         ^^^^^^^^^^^^^^^^^^^
++
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:236:9
++   |
++LL |         fn new(_: String) -> String;
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:271:9
++   |
++LL | /         fn new() -> (u32, u32) {
++LL | |             unimplemented!();
++LL | |         }
++   | |_________^
++
++error: methods called `new` usually return `Self`
++  --> $DIR/new_ret_no_self.rs:298:9
++   |
++LL | /         fn new() -> *mut V {
++LL | |             unimplemented!();
++LL | |         }
++   | |_________^
++
++error: aborting due to 10 previous errors
 +
index 076692e6445175da398e3ae788c803c5b57ba901,0000000000000000000000000000000000000000..07d7f0b45b0c2f2171cd29c29a4360deb7cff1ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,44 @@@
 +// run-rustfix
 +
 +#![allow(unused_imports, clippy::redundant_clone)]
 +#![warn(clippy::option_as_ref_deref)]
 +
 +use std::ffi::{CString, OsString};
 +use std::ops::{Deref, DerefMut};
 +use std::path::PathBuf;
 +
 +fn main() {
 +    let mut opt = Some(String::from("123"));
 +
 +    let _ = opt.clone().as_deref().map(str::len);
 +
 +    #[rustfmt::skip]
 +    let _ = opt.clone().as_deref()
 +        .map(str::len);
 +
 +    let _ = opt.as_deref_mut();
 +
 +    let _ = opt.as_deref();
 +    let _ = opt.as_deref();
 +    let _ = opt.as_deref_mut();
 +    let _ = opt.as_deref_mut();
 +    let _ = Some(CString::new(vec![]).unwrap()).as_deref();
 +    let _ = Some(OsString::new()).as_deref();
 +    let _ = Some(PathBuf::new()).as_deref();
 +    let _ = Some(Vec::<()>::new()).as_deref();
 +    let _ = Some(Vec::<()>::new()).as_deref_mut();
 +
 +    let _ = opt.as_deref();
 +    let _ = opt.clone().as_deref_mut().map(|x| x.len());
 +
 +    let vc = vec![String::new()];
 +    let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
 +
 +    let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
 +
 +    let _ = opt.as_deref();
 +    let _ = opt.as_deref_mut();
++
++    // Issue #5927
++    let _ = opt.as_deref();
 +}
index 3bf5f715f8339525b8ad547d75eea77a96b0c1f2,0000000000000000000000000000000000000000..6ae059c9425d35480c7afcc00ab7e6b63b0db3cf
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,47 @@@
 +// run-rustfix
 +
 +#![allow(unused_imports, clippy::redundant_clone)]
 +#![warn(clippy::option_as_ref_deref)]
 +
 +use std::ffi::{CString, OsString};
 +use std::ops::{Deref, DerefMut};
 +use std::path::PathBuf;
 +
 +fn main() {
 +    let mut opt = Some(String::from("123"));
 +
 +    let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
 +
 +    #[rustfmt::skip]
 +    let _ = opt.clone()
 +        .as_ref().map(
 +            Deref::deref
 +        )
 +        .map(str::len);
 +
 +    let _ = opt.as_mut().map(DerefMut::deref_mut);
 +
 +    let _ = opt.as_ref().map(String::as_str);
 +    let _ = opt.as_ref().map(|x| x.as_str());
 +    let _ = opt.as_mut().map(String::as_mut_str);
 +    let _ = opt.as_mut().map(|x| x.as_mut_str());
 +    let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
 +    let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
 +    let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
 +    let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
 +    let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
 +
 +    let _ = opt.as_ref().map(|x| x.deref());
 +    let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
 +
 +    let vc = vec![String::new()];
 +    let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
 +
 +    let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
 +
 +    let _ = opt.as_ref().map(|x| &**x);
 +    let _ = opt.as_mut().map(|x| &mut **x);
++
++    // Issue #5927
++    let _ = opt.as_ref().map(std::ops::Deref::deref);
 +}
index a106582a633232b4bfcdc95c78308440d2480137,0000000000000000000000000000000000000000..62f28232475282a1a51ade866365560ec6031386
mode 100644,000000..100644
--- /dev/null
@@@ -1,104 -1,0 +1,110 @@@
- error: aborting due to 16 previous errors
 +error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:13:13
 +   |
 +LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
 +   |
 +   = note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
 +
 +error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:16:13
 +   |
 +LL |       let _ = opt.clone()
 +   |  _____________^
 +LL | |         .as_ref().map(
 +LL | |             Deref::deref
 +LL | |         )
 +   | |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
 +
 +error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:22:13
 +   |
 +LL |     let _ = opt.as_mut().map(DerefMut::deref_mut);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 +
 +error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:24:13
 +   |
 +LL |     let _ = opt.as_ref().map(String::as_str);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 +
 +error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:25:13
 +   |
 +LL |     let _ = opt.as_ref().map(|x| x.as_str());
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 +
 +error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:26:13
 +   |
 +LL |     let _ = opt.as_mut().map(String::as_mut_str);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 +
 +error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:27:13
 +   |
 +LL |     let _ = opt.as_mut().map(|x| x.as_mut_str());
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 +
 +error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:28:13
 +   |
 +LL |     let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
 +
 +error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:29:13
 +   |
 +LL |     let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
 +
 +error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:30:13
 +   |
 +LL |     let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
 +
 +error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:31:13
 +   |
 +LL |     let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
 +
 +error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:32:13
 +   |
 +LL |     let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
 +
 +error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:34:13
 +   |
 +LL |     let _ = opt.as_ref().map(|x| x.deref());
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 +
 +error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:35:13
 +   |
 +LL |     let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
 +
 +error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
 +  --> $DIR/option_as_ref_deref.rs:42:13
 +   |
 +LL |     let _ = opt.as_ref().map(|x| &**x);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 +
 +error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
 +  --> $DIR/option_as_ref_deref.rs:43:13
 +   |
 +LL |     let _ = opt.as_mut().map(|x| &mut **x);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 +
++error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
++  --> $DIR/option_as_ref_deref.rs:46:13
++   |
++LL |     let _ = opt.as_ref().map(std::ops::Deref::deref);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
++
++error: aborting due to 17 previous errors
 +
index 4d284ae1319d321a4d867e91f10e71ae317bacd9,0000000000000000000000000000000000000000..163bd044c178ee37fdcbc91763aec383e78b69bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,53 -1,0 +1,61 @@@
 +// run-rustfix
 +#![warn(clippy::precedence)]
 +#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
 +#![allow(clippy::identity_op)]
 +#![allow(clippy::eq_op)]
 +
 +macro_rules! trip {
 +    ($a:expr) => {
 +        match $a & 0b1111_1111u8 {
 +            0 => println!("a is zero ({})", $a),
 +            _ => println!("a is {}", $a),
 +        }
 +    };
 +}
 +
 +fn main() {
 +    1 << (2 + 3);
 +    (1 + 2) << 3;
 +    4 >> (1 + 1);
 +    (1 + 3) >> 2;
 +    1 ^ (1 - 1);
 +    3 | (2 - 1);
 +    3 & (5 - 2);
 +    -(1i32.abs());
 +    -(1f32.abs());
 +
 +    // These should not trigger an error
 +    let _ = (-1i32).abs();
 +    let _ = (-1f32).abs();
 +    let _ = -(1i32).abs();
 +    let _ = -(1f32).abs();
 +    let _ = -(1i32.abs());
 +    let _ = -(1f32.abs());
 +
 +    // Odd functions should not trigger an error
 +    let _ = -1f64.asin();
 +    let _ = -1f64.asinh();
 +    let _ = -1f64.atan();
 +    let _ = -1f64.atanh();
 +    let _ = -1f64.cbrt();
 +    let _ = -1f64.fract();
 +    let _ = -1f64.round();
 +    let _ = -1f64.signum();
 +    let _ = -1f64.sin();
 +    let _ = -1f64.sinh();
 +    let _ = -1f64.tan();
 +    let _ = -1f64.tanh();
 +    let _ = -1f64.to_degrees();
 +    let _ = -1f64.to_radians();
 +
++    // Chains containing any non-odd function should trigger (issue #5924)
++    let _ = -(1.0_f64.cos().cos());
++    let _ = -(1.0_f64.cos().sin());
++    let _ = -(1.0_f64.sin().cos());
++
++    // Chains of odd functions shouldn't trigger
++    let _ = -1f64.sin().sin();
++
 +    let b = 3;
 +    trip!(b * 8);
 +}
index 2d08e82f349ade91eb20d8fa8adb3f040a6d2908,0000000000000000000000000000000000000000..8c849e3209b088909668d26df45246472be9defc
mode 100644,000000..100644
--- /dev/null
@@@ -1,53 -1,0 +1,61 @@@
 +// run-rustfix
 +#![warn(clippy::precedence)]
 +#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
 +#![allow(clippy::identity_op)]
 +#![allow(clippy::eq_op)]
 +
 +macro_rules! trip {
 +    ($a:expr) => {
 +        match $a & 0b1111_1111u8 {
 +            0 => println!("a is zero ({})", $a),
 +            _ => println!("a is {}", $a),
 +        }
 +    };
 +}
 +
 +fn main() {
 +    1 << 2 + 3;
 +    1 + 2 << 3;
 +    4 >> 1 + 1;
 +    1 + 3 >> 2;
 +    1 ^ 1 - 1;
 +    3 | 2 - 1;
 +    3 & 5 - 2;
 +    -1i32.abs();
 +    -1f32.abs();
 +
 +    // These should not trigger an error
 +    let _ = (-1i32).abs();
 +    let _ = (-1f32).abs();
 +    let _ = -(1i32).abs();
 +    let _ = -(1f32).abs();
 +    let _ = -(1i32.abs());
 +    let _ = -(1f32.abs());
 +
 +    // Odd functions should not trigger an error
 +    let _ = -1f64.asin();
 +    let _ = -1f64.asinh();
 +    let _ = -1f64.atan();
 +    let _ = -1f64.atanh();
 +    let _ = -1f64.cbrt();
 +    let _ = -1f64.fract();
 +    let _ = -1f64.round();
 +    let _ = -1f64.signum();
 +    let _ = -1f64.sin();
 +    let _ = -1f64.sinh();
 +    let _ = -1f64.tan();
 +    let _ = -1f64.tanh();
 +    let _ = -1f64.to_degrees();
 +    let _ = -1f64.to_radians();
 +
++    // Chains containing any non-odd function should trigger (issue #5924)
++    let _ = -1.0_f64.cos().cos();
++    let _ = -1.0_f64.cos().sin();
++    let _ = -1.0_f64.sin().cos();
++
++    // Chains of odd functions shouldn't trigger
++    let _ = -1f64.sin().sin();
++
 +    let b = 3;
 +    trip!(b * 8);
 +}
index a2ed5392bfc7c643593dbf24434ab8c05d1d3c93,0000000000000000000000000000000000000000..03d585b39750a6cc3932fdf8c539063c76e28b1d
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,76 @@@
- error: aborting due to 9 previous errors
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:17:5
 +   |
 +LL |     1 << 2 + 3;
 +   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)`
 +   |
 +   = note: `-D clippy::precedence` implied by `-D warnings`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:18:5
 +   |
 +LL |     1 + 2 << 3;
 +   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:19:5
 +   |
 +LL |     4 >> 1 + 1;
 +   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:20:5
 +   |
 +LL |     1 + 3 >> 2;
 +   |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:21:5
 +   |
 +LL |     1 ^ 1 - 1;
 +   |     ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:22:5
 +   |
 +LL |     3 | 2 - 1;
 +   |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)`
 +
 +error: operator precedence can trip the unwary
 +  --> $DIR/precedence.rs:23:5
 +   |
 +LL |     3 & 5 - 2;
 +   |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)`
 +
 +error: unary minus has lower precedence than method call
 +  --> $DIR/precedence.rs:24:5
 +   |
 +LL |     -1i32.abs();
 +   |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())`
 +
 +error: unary minus has lower precedence than method call
 +  --> $DIR/precedence.rs:25:5
 +   |
 +LL |     -1f32.abs();
 +   |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())`
 +
++error: unary minus has lower precedence than method call
++  --> $DIR/precedence.rs:52:13
++   |
++LL |     let _ = -1.0_f64.cos().cos();
++   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())`
++
++error: unary minus has lower precedence than method call
++  --> $DIR/precedence.rs:53:13
++   |
++LL |     let _ = -1.0_f64.cos().sin();
++   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())`
++
++error: unary minus has lower precedence than method call
++  --> $DIR/precedence.rs:54:13
++   |
++LL |     let _ = -1.0_f64.sin().cos();
++   |             ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())`
++
++error: aborting due to 12 previous errors
 +
index 266358334587d0a6edb4a94e328e77d1a6515c93,0000000000000000000000000000000000000000..6514fd6d1ac76bbe7ebbbd37453af5002e3c3308
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,48 @@@
- pub fn test6(a: Box<bool>) {}
 +// run-rustfix
 +#![warn(clippy::all)]
 +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
 +#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
 +
 +use std::boxed::Box;
 +use std::rc::Rc;
 +
 +pub struct MyStruct {}
 +
 +pub struct SubT<T> {
 +    foo: T,
 +}
 +
 +pub enum MyEnum {
 +    One,
 +    Two,
 +}
 +
 +// Rc<&T>
 +
 +pub fn test1<T>(foo: &T) {}
 +
 +pub fn test2(foo: &MyStruct) {}
 +
 +pub fn test3(foo: &MyEnum) {}
 +
 +pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
 +
 +// Rc<Rc<T>>
 +
 +pub fn test5(a: Rc<bool>) {}
 +
 +// Rc<Box<T>>
 +
++pub fn test6(a: Rc<bool>) {}
 +
 +// Box<&T>
 +
 +pub fn test7<T>(foo: &T) {}
 +
 +pub fn test8(foo: &MyStruct) {}
 +
 +pub fn test9(foo: &MyEnum) {}
 +
 +pub fn test10_neg(foo: Box<SubT<&usize>>) {}
 +
 +fn main() {}
index eaa57ce3024b604243166b7e78bcf1d58dc6f536,0000000000000000000000000000000000000000..92e4f67f5db6e40e6f2f0f9bd8ed422b3ec32c0c
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,52 @@@
-    |                 ^^^^^^^^^^^^^ help: try: `Box<bool>`
 +error: usage of `Rc<&T>`
 +  --> $DIR/redundant_allocation.rs:22:22
 +   |
 +LL | pub fn test1<T>(foo: Rc<&T>) {}
 +   |                      ^^^^^^ help: try: `&T`
 +   |
 +   = note: `-D clippy::redundant-allocation` implied by `-D warnings`
 +
 +error: usage of `Rc<&T>`
 +  --> $DIR/redundant_allocation.rs:24:19
 +   |
 +LL | pub fn test2(foo: Rc<&MyStruct>) {}
 +   |                   ^^^^^^^^^^^^^ help: try: `&MyStruct`
 +
 +error: usage of `Rc<&T>`
 +  --> $DIR/redundant_allocation.rs:26:19
 +   |
 +LL | pub fn test3(foo: Rc<&MyEnum>) {}
 +   |                   ^^^^^^^^^^^ help: try: `&MyEnum`
 +
 +error: usage of `Rc<Rc<T>>`
 +  --> $DIR/redundant_allocation.rs:32:17
 +   |
 +LL | pub fn test5(a: Rc<Rc<bool>>) {}
 +   |                 ^^^^^^^^^^^^ help: try: `Rc<bool>`
 +
 +error: usage of `Rc<Box<T>>`
 +  --> $DIR/redundant_allocation.rs:36:17
 +   |
 +LL | pub fn test6(a: Rc<Box<bool>>) {}
++   |                 ^^^^^^^^^^^^^ help: try: `Rc<bool>`
 +
 +error: usage of `Box<&T>`
 +  --> $DIR/redundant_allocation.rs:40:22
 +   |
 +LL | pub fn test7<T>(foo: Box<&T>) {}
 +   |                      ^^^^^^^ help: try: `&T`
 +
 +error: usage of `Box<&T>`
 +  --> $DIR/redundant_allocation.rs:42:19
 +   |
 +LL | pub fn test8(foo: Box<&MyStruct>) {}
 +   |                   ^^^^^^^^^^^^^^ help: try: `&MyStruct`
 +
 +error: usage of `Box<&T>`
 +  --> $DIR/redundant_allocation.rs:44:19
 +   |
 +LL | pub fn test9(foo: Box<&MyEnum>) {}
 +   |                   ^^^^^^^^^^^^ help: try: `&MyEnum`
 +
 +error: aborting due to 8 previous errors
 +
index 79f276634619e277c24cef3069afe85953948210,0000000000000000000000000000000000000000..2735e41738f0d0ef4555759f74260fa5e82bca38
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- error: try not to call a closure in the expression where it is declared.
++error: try not to call a closure in the expression where it is declared
 +  --> $DIR/redundant_closure_call_early.rs:9:17
 +   |
 +LL |     let mut k = (|m| m + 1)(i);
 +   |                 ^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
 +
- error: try not to call a closure in the expression where it is declared.
++error: try not to call a closure in the expression where it is declared
 +  --> $DIR/redundant_closure_call_early.rs:12:9
 +   |
 +LL |     k = (|a, b| a * b)(1, 5);
 +   |         ^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 2 previous errors
 +
index 644161d9f5d885eb24da0c187bfcd5e63ffa1352,0000000000000000000000000000000000000000..afd704ef12a934f913454334a42bd68c5a95a954
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,10 @@@
- error: try not to call a closure in the expression where it is declared.
++error: try not to call a closure in the expression where it is declared
 +  --> $DIR/redundant_closure_call_fixable.rs:7:13
 +   |
 +LL |     let a = (|| 42)();
 +   |             ^^^^^^^^^ help: try doing something like: `42`
 +   |
 +   = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
 +
 +error: aborting due to previous error
 +
index e29a1dce0c7e8f040f7dd3f262e505fbf4d21d9a,0000000000000000000000000000000000000000..1f4864b72895bf10142574e214bdfe352eba896a
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,39 @@@
 +// non rustfixable, see redundant_closure_call_fixable.rs
 +
 +#![warn(clippy::redundant_closure_call)]
 +
 +fn main() {
 +    let mut i = 1;
 +
 +    // don't lint here, the closure is used more than once
 +    let closure = |i| i + 1;
 +    i = closure(3);
 +    i = closure(4);
 +
 +    // lint here
 +    let redun_closure = || 1;
 +    i = redun_closure();
 +
 +    // shadowed closures are supported, lint here
 +    let shadowed_closure = || 1;
 +    i = shadowed_closure();
 +    let shadowed_closure = || 2;
 +    i = shadowed_closure();
 +
 +    // don't lint here
 +    let shadowed_closure = || 2;
 +    i = shadowed_closure();
 +    i = shadowed_closure();
++
++    // Fix FP in #5916
++    let mut x;
++    let create = || 2 * 2;
++    x = create();
++    fun(move || {
++        x = create();
++    })
++}
++
++fn fun<T: 'static + FnMut()>(mut f: T) {
++    f();
 +}
index ff1088f86f6470cc2c41256fdd8746d3161bb23b,0000000000000000000000000000000000000000..bfe27e020445c77b83c4ddfb14f773eb4ee36b85
mode 100644,000000..100644
--- /dev/null
@@@ -1,89 -1,0 +1,97 @@@
 +#![warn(clippy::same_item_push)]
 +
 +fn mutate_increment(x: &mut u8) -> u8 {
 +    *x += 1;
 +    *x
 +}
 +
 +fn increment(x: u8) -> u8 {
 +    x + 1
 +}
 +
 +fn main() {
 +    // Test for basic case
 +    let mut spaces = Vec::with_capacity(10);
 +    for _ in 0..10 {
 +        spaces.push(vec![b' ']);
 +    }
 +
 +    let mut vec2: Vec<u8> = Vec::new();
 +    let item = 2;
 +    for _ in 5..=20 {
 +        vec2.push(item);
 +    }
 +
 +    let mut vec3: Vec<u8> = Vec::new();
 +    for _ in 0..15 {
 +        let item = 2;
 +        vec3.push(item);
 +    }
 +
 +    let mut vec4: Vec<u8> = Vec::new();
 +    for _ in 0..15 {
 +        vec4.push(13);
 +    }
 +
 +    // Suggestion should not be given as pushed variable can mutate
 +    let mut vec5: Vec<u8> = Vec::new();
 +    let mut item: u8 = 2;
 +    for _ in 0..30 {
 +        vec5.push(mutate_increment(&mut item));
 +    }
 +
 +    let mut vec6: Vec<u8> = Vec::new();
 +    let mut item: u8 = 2;
 +    let mut item2 = &mut mutate_increment(&mut item);
 +    for _ in 0..30 {
 +        vec6.push(mutate_increment(item2));
 +    }
 +
 +    let mut vec7: Vec<usize> = Vec::new();
 +    for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() {
 +        vec7.push(a);
 +    }
 +
 +    let mut vec8: Vec<u8> = Vec::new();
 +    for i in 0..30 {
 +        vec8.push(increment(i));
 +    }
 +
 +    let mut vec9: Vec<u8> = Vec::new();
 +    for i in 0..30 {
 +        vec9.push(i + i * i);
 +    }
 +
 +    // Suggestion should not be given as there are multiple pushes that are not the same
 +    let mut vec10: Vec<u8> = Vec::new();
 +    let item: u8 = 2;
 +    for _ in 0..30 {
 +        vec10.push(item);
 +        vec10.push(item * 2);
 +    }
 +
 +    // Suggestion should not be given as Vec is not involved
 +    for _ in 0..5 {
 +        println!("Same Item Push");
 +    }
 +
 +    struct A {
 +        kind: u32,
 +    }
 +    let mut vec_a: Vec<A> = Vec::new();
 +    for i in 0..30 {
 +        vec_a.push(A { kind: i });
 +    }
 +    let mut vec12: Vec<u8> = Vec::new();
 +    for a in vec_a {
 +        vec12.push(2u8.pow(a.kind));
 +    }
++
++    // Fix #5902
++    let mut vec13: Vec<u8> = Vec::new();
++    let mut item = 0;
++    for _ in 0..10 {
++        vec13.push(item);
++        item += 10;
++    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a7cbb9cd78b151cb82b9f415c59a170be1541e2e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,67 @@@
++#![warn(clippy::self_assignment)]
++
++pub struct S<'a> {
++    a: i32,
++    b: [i32; 10],
++    c: Vec<Vec<i32>>,
++    e: &'a mut i32,
++    f: &'a mut i32,
++}
++
++pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
++    a = a;
++    *b = *b;
++    s = s;
++    s.a = s.a;
++    s.b[10] = s.b[5 + 5];
++    s.c[0][1] = s.c[0][1];
++    s.b[a] = s.b[a];
++    *s.e = *s.e;
++    s.b[a + 10] = s.b[10 + a];
++
++    let mut t = (0, 1);
++    t.1 = t.1;
++    t.0 = (t.0);
++}
++
++pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) {
++    dbg!(&a);
++    a = *b;
++    dbg!(&a);
++    s.b[1] += s.b[1];
++    s.b[1] = s.b[2];
++    s.c[1][0] = s.c[0][1];
++    s.b[a] = s.b[*b];
++    s.b[a + 10] = s.b[a + 11];
++    *s.e = *s.f;
++
++    let mut t = (0, 1);
++    t.0 = t.1;
++}
++
++#[allow(clippy::eval_order_dependence)]
++pub fn negatives_side_effects() {
++    let mut v = vec![1, 2, 3, 4, 5];
++    let mut i = 0;
++    v[{
++        i += 1;
++        i
++    }] = v[{
++        i += 1;
++        i
++    }];
++
++    fn next(n: &mut usize) -> usize {
++        let v = *n;
++        *n += 1;
++        v
++    }
++
++    let mut w = vec![1, 2, 3, 4, 5];
++    let mut i = 0;
++    let i = &mut i;
++    w[next(i)] = w[next(i)];
++    w[next(i)] = w[next(i)];
++}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..826e0d0ba888dacda4a21b006fed23157c67f22f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,70 @@@
++error: self-assignment of `a` to `a`
++  --> $DIR/self_assignment.rs:12:5
++   |
++LL |     a = a;
++   |     ^^^^^
++   |
++   = note: `-D clippy::self-assignment` implied by `-D warnings`
++
++error: self-assignment of `*b` to `*b`
++  --> $DIR/self_assignment.rs:13:5
++   |
++LL |     *b = *b;
++   |     ^^^^^^^
++
++error: self-assignment of `s` to `s`
++  --> $DIR/self_assignment.rs:14:5
++   |
++LL |     s = s;
++   |     ^^^^^
++
++error: self-assignment of `s.a` to `s.a`
++  --> $DIR/self_assignment.rs:15:5
++   |
++LL |     s.a = s.a;
++   |     ^^^^^^^^^
++
++error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
++  --> $DIR/self_assignment.rs:16:5
++   |
++LL |     s.b[10] = s.b[5 + 5];
++   |     ^^^^^^^^^^^^^^^^^^^^
++
++error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
++  --> $DIR/self_assignment.rs:17:5
++   |
++LL |     s.c[0][1] = s.c[0][1];
++   |     ^^^^^^^^^^^^^^^^^^^^^
++
++error: self-assignment of `s.b[a]` to `s.b[a]`
++  --> $DIR/self_assignment.rs:18:5
++   |
++LL |     s.b[a] = s.b[a];
++   |     ^^^^^^^^^^^^^^^
++
++error: self-assignment of `*s.e` to `*s.e`
++  --> $DIR/self_assignment.rs:19:5
++   |
++LL |     *s.e = *s.e;
++   |     ^^^^^^^^^^^
++
++error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]`
++  --> $DIR/self_assignment.rs:20:5
++   |
++LL |     s.b[a + 10] = s.b[10 + a];
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: self-assignment of `t.1` to `t.1`
++  --> $DIR/self_assignment.rs:23:5
++   |
++LL |     t.1 = t.1;
++   |     ^^^^^^^^^
++
++error: self-assignment of `(t.0)` to `t.0`
++  --> $DIR/self_assignment.rs:24:5
++   |
++LL |     t.0 = (t.0);
++   |     ^^^^^^^^^^^
++
++error: aborting due to 11 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6c5ffe6aba8b7b7c1e4923c957617f6df31ffc64
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,83 @@@
++// edition:2018
++
++#![warn(clippy::all, clippy::pedantic)]
++#![allow(
++    clippy::missing_errors_doc,
++    clippy::needless_pass_by_value,
++    clippy::must_use_candidate,
++    clippy::unused_self,
++    clippy::needless_lifetimes,
++    clippy::missing_safety_doc,
++    clippy::wrong_self_convention
++)]
++
++use std::ops::Mul;
++use std::rc::{self, Rc};
++use std::sync::{self, Arc};
++
++fn main() {}
++
++pub struct T1;
++impl T1 {
++    // corner cases: should not lint
++
++    // no error, not public interface
++    pub(crate) fn drop(&mut self) {}
++
++    // no error, private function
++    fn neg(self) -> Self {
++        self
++    }
++
++    // no error, private function
++    fn eq(&self, other: Self) -> bool {
++        true
++    }
++
++    // No error; self is a ref.
++    fn sub(&self, other: Self) -> &Self {
++        self
++    }
++
++    // No error; different number of arguments.
++    fn div(self) -> Self {
++        self
++    }
++
++    // No error; wrong return type.
++    fn rem(self, other: Self) {}
++
++    // Fine
++    fn into_u32(self) -> u32 {
++        0
++    }
++
++    fn into_u16(&self) -> u16 {
++        0
++    }
++
++    fn to_something(self) -> u32 {
++        0
++    }
++
++    fn new(self) -> Self {
++        unimplemented!();
++    }
++
++    pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> {
++        unimplemented!();
++    }
++}
++
++pub struct T2;
++impl T2 {
++    // Shouldn't trigger lint as it is unsafe.
++    pub unsafe fn add(self, rhs: Self) -> Self {
++        self
++    }
++
++    // Should not trigger lint since this is an async function.
++    pub async fn next(&mut self) -> Option<Self> {
++        None
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f8d248fc98d82a2db4ac7ae5d106bfe10d7fe782
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,87 @@@
++// edition:2018
++
++#![warn(clippy::all, clippy::pedantic)]
++#![allow(
++    clippy::missing_errors_doc,
++    clippy::needless_pass_by_value,
++    clippy::must_use_candidate,
++    clippy::unused_self,
++    clippy::needless_lifetimes,
++    clippy::missing_safety_doc,
++    clippy::wrong_self_convention
++)]
++
++use std::ops::Mul;
++use std::rc::{self, Rc};
++use std::sync::{self, Arc};
++
++fn main() {}
++pub struct T;
++
++impl T {
++    // *****************************************
++    // trait method list part 1, should lint all
++    // *****************************************
++    pub fn add(self, other: T) -> T {
++        unimplemented!()
++    }
++
++    pub fn as_mut(&mut self) -> &mut T {
++        unimplemented!()
++    }
++
++    pub fn as_ref(&self) -> &T {
++        unimplemented!()
++    }
++
++    pub fn bitand(self, rhs: T) -> T {
++        unimplemented!()
++    }
++
++    pub fn bitor(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn bitxor(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn borrow(&self) -> &str {
++        unimplemented!()
++    }
++
++    pub fn borrow_mut(&mut self) -> &mut str {
++        unimplemented!()
++    }
++
++    pub fn clone(&self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn cmp(&self, other: &Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn default() -> Self {
++        unimplemented!()
++    }
++
++    pub fn deref(&self) -> &Self {
++        unimplemented!()
++    }
++
++    pub fn deref_mut(&mut self) -> &mut Self {
++        unimplemented!()
++    }
++
++    pub fn div(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn drop(&mut self) {
++        unimplemented!()
++    }
++    // **********
++    // part 1 end
++    // **********
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2b7d4628c3fa02b703e9a58cb98b73d4a1dd6489
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,143 @@@
++error: method `add` can be confused for the standard trait method `std::ops::Add::add`
++  --> $DIR/method_list_1.rs:25:5
++   |
++LL | /     pub fn add(self, other: T) -> T {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
++   = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
++
++error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
++  --> $DIR/method_list_1.rs:29:5
++   |
++LL | /     pub fn as_mut(&mut self) -> &mut T {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
++
++error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
++  --> $DIR/method_list_1.rs:33:5
++   |
++LL | /     pub fn as_ref(&self) -> &T {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
++
++error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
++  --> $DIR/method_list_1.rs:37:5
++   |
++LL | /     pub fn bitand(self, rhs: T) -> T {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
++
++error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
++  --> $DIR/method_list_1.rs:41:5
++   |
++LL | /     pub fn bitor(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
++
++error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
++  --> $DIR/method_list_1.rs:45:5
++   |
++LL | /     pub fn bitxor(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
++
++error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
++  --> $DIR/method_list_1.rs:49:5
++   |
++LL | /     pub fn borrow(&self) -> &str {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
++
++error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
++  --> $DIR/method_list_1.rs:53:5
++   |
++LL | /     pub fn borrow_mut(&mut self) -> &mut str {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
++
++error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
++  --> $DIR/method_list_1.rs:57:5
++   |
++LL | /     pub fn clone(&self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
++
++error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
++  --> $DIR/method_list_1.rs:61:5
++   |
++LL | /     pub fn cmp(&self, other: &Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
++
++error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
++  --> $DIR/method_list_1.rs:69:5
++   |
++LL | /     pub fn deref(&self) -> &Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
++
++error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
++  --> $DIR/method_list_1.rs:73:5
++   |
++LL | /     pub fn deref_mut(&mut self) -> &mut Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
++
++error: method `div` can be confused for the standard trait method `std::ops::Div::div`
++  --> $DIR/method_list_1.rs:77:5
++   |
++LL | /     pub fn div(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
++
++error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
++  --> $DIR/method_list_1.rs:81:5
++   |
++LL | /     pub fn drop(&mut self) {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
++
++error: aborting due to 14 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ed5e0d384bf5040c0d90135bc6cd65ab5832306d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,88 @@@
++// edition:2018
++
++#![warn(clippy::all, clippy::pedantic)]
++#![allow(
++    clippy::missing_errors_doc,
++    clippy::needless_pass_by_value,
++    clippy::must_use_candidate,
++    clippy::unused_self,
++    clippy::needless_lifetimes,
++    clippy::missing_safety_doc,
++    clippy::wrong_self_convention
++)]
++
++use std::ops::Mul;
++use std::rc::{self, Rc};
++use std::sync::{self, Arc};
++
++fn main() {}
++pub struct T;
++
++impl T {
++    // *****************************************
++    // trait method list part 2, should lint all
++    // *****************************************
++
++    pub fn eq(&self, other: &Self) -> bool {
++        unimplemented!()
++    }
++
++    pub fn from_iter<T>(iter: T) -> Self {
++        unimplemented!()
++    }
++
++    pub fn from_str(s: &str) -> Result<Self, Self> {
++        unimplemented!()
++    }
++
++    pub fn hash(&self, state: &mut T) {
++        unimplemented!()
++    }
++
++    pub fn index(&self, index: usize) -> &Self {
++        unimplemented!()
++    }
++
++    pub fn index_mut(&mut self, index: usize) -> &mut Self {
++        unimplemented!()
++    }
++
++    pub fn into_iter(self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn mul(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn neg(self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn next(&mut self) -> Option<Self> {
++        unimplemented!()
++    }
++
++    pub fn not(self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn rem(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn shl(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn shr(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++
++    pub fn sub(self, rhs: Self) -> Self {
++        unimplemented!()
++    }
++    // **********
++    // part 2 end
++    // **********
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b6fd435695698e6ca47adee8a423824472e6b14d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,153 @@@
++error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
++  --> $DIR/method_list_2.rs:26:5
++   |
++LL | /     pub fn eq(&self, other: &Self) -> bool {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
++   = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
++
++error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
++  --> $DIR/method_list_2.rs:30:5
++   |
++LL | /     pub fn from_iter<T>(iter: T) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
++
++error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
++  --> $DIR/method_list_2.rs:34:5
++   |
++LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
++
++error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
++  --> $DIR/method_list_2.rs:38:5
++   |
++LL | /     pub fn hash(&self, state: &mut T) {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
++
++error: method `index` can be confused for the standard trait method `std::ops::Index::index`
++  --> $DIR/method_list_2.rs:42:5
++   |
++LL | /     pub fn index(&self, index: usize) -> &Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
++
++error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
++  --> $DIR/method_list_2.rs:46:5
++   |
++LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
++
++error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
++  --> $DIR/method_list_2.rs:50:5
++   |
++LL | /     pub fn into_iter(self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
++
++error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
++  --> $DIR/method_list_2.rs:54:5
++   |
++LL | /     pub fn mul(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
++
++error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
++  --> $DIR/method_list_2.rs:58:5
++   |
++LL | /     pub fn neg(self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
++
++error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
++  --> $DIR/method_list_2.rs:62:5
++   |
++LL | /     pub fn next(&mut self) -> Option<Self> {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
++
++error: method `not` can be confused for the standard trait method `std::ops::Not::not`
++  --> $DIR/method_list_2.rs:66:5
++   |
++LL | /     pub fn not(self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
++
++error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
++  --> $DIR/method_list_2.rs:70:5
++   |
++LL | /     pub fn rem(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
++
++error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
++  --> $DIR/method_list_2.rs:74:5
++   |
++LL | /     pub fn shl(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
++
++error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
++  --> $DIR/method_list_2.rs:78:5
++   |
++LL | /     pub fn shr(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
++
++error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
++  --> $DIR/method_list_2.rs:82:5
++   |
++LL | /     pub fn sub(self, rhs: Self) -> Self {
++LL | |         unimplemented!()
++LL | |     }
++   | |_____^
++   |
++   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
++
++error: aborting due to 15 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0812c026a644fbdd84f05569edc5cf954a8a109f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++// run-rustfix
++#![warn(clippy::single_char_push_str)]
++
++fn main() {
++    let mut string = String::new();
++    string.push('R');
++    string.push('\'');
++
++    string.push('u');
++    string.push_str("st");
++    string.push_str("");
++    string.push('\x52');
++    string.push('\u{0052}');
++    string.push('a');
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ab293bbe4eeb5ce8171ec28f610410a45f2d5cb8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++// run-rustfix
++#![warn(clippy::single_char_push_str)]
++
++fn main() {
++    let mut string = String::new();
++    string.push_str("R");
++    string.push_str("'");
++
++    string.push('u');
++    string.push_str("st");
++    string.push_str("");
++    string.push_str("\x52");
++    string.push_str("\u{0052}");
++    string.push_str(r##"a"##);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0e9bdaa23e7e8474accd8321884cc0861db8405c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++error: calling `push_str()` using a single-character string literal
++  --> $DIR/single_char_push_str.rs:6:5
++   |
++LL |     string.push_str("R");
++   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')`
++   |
++   = note: `-D clippy::single-char-push-str` implied by `-D warnings`
++
++error: calling `push_str()` using a single-character string literal
++  --> $DIR/single_char_push_str.rs:7:5
++   |
++LL |     string.push_str("'");
++   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
++
++error: calling `push_str()` using a single-character string literal
++  --> $DIR/single_char_push_str.rs:12:5
++   |
++LL |     string.push_str("/x52");
++   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
++
++error: calling `push_str()` using a single-character string literal
++  --> $DIR/single_char_push_str.rs:13:5
++   |
++LL |     string.push_str("/u{0052}");
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
++
++error: calling `push_str()` using a single-character string literal
++  --> $DIR/single_char_push_str.rs:14:5
++   |
++LL |     string.push_str(r##"a"##);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
++
++error: aborting due to 5 previous errors
++
index b0b729ede48e5cccde3396c0920baaf2cc3d7a33,0000000000000000000000000000000000000000..780389f32bc1c6c721e7549880146870c53dd685
mode 100644,000000..100644
--- /dev/null
@@@ -1,46 -1,0 +1,46 @@@
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `i32`
 +  --> $DIR/stable_sort_primitive.rs:7:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +   |
 +   = note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `bool`
 +  --> $DIR/stable_sort_primitive.rs:9:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `char`
 +  --> $DIR/stable_sort_primitive.rs:11:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `str`
 +  --> $DIR/stable_sort_primitive.rs:13:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `tuple`
 +  --> $DIR/stable_sort_primitive.rs:15:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `array`
 +  --> $DIR/stable_sort_primitive.rs:17:5
 +   |
 +LL |     vec.sort();
 +   |     ^^^^^^^^^^ help: try: `vec.sort_unstable()`
 +
- error: Use sort_unstable instead of sort
++error: used sort instead of sort_unstable to sort primitive type `i32`
 +  --> $DIR/stable_sort_primitive.rs:19:5
 +   |
 +LL |     arr.sort();
 +   |     ^^^^^^^^^^ help: try: `arr.sort_unstable()`
 +
 +error: aborting due to 7 previous errors
 +
index 60c2f3ec9b652159db0b19696b1139ca9a8bff4c,0000000000000000000000000000000000000000..5c280efac1a876dbb849b7c81940b6d3db1b48ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,120 -1,0 +1,170 @@@
- use std::ops::{Add, AddAssign, BitOrAssign, Div, DivAssign, Mul, MulAssign, Sub};
 +#![warn(clippy::suspicious_arithmetic_impl)]
++use std::ops::{
++    Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub,
++};
 +
 +#[derive(Copy, Clone)]
 +struct Foo(u32);
 +
 +impl Add for Foo {
 +    type Output = Foo;
 +
 +    fn add(self, other: Self) -> Self {
 +        Foo(self.0 - other.0)
 +    }
 +}
 +
 +impl AddAssign for Foo {
 +    fn add_assign(&mut self, other: Foo) {
 +        *self = *self - other;
 +    }
 +}
 +
 +impl BitOrAssign for Foo {
 +    fn bitor_assign(&mut self, other: Foo) {
 +        let idx = other.0;
 +        self.0 |= 1 << idx; // OK: BinOpKind::Shl part of AssignOp as child node
 +    }
 +}
 +
 +impl MulAssign for Foo {
 +    fn mul_assign(&mut self, other: Foo) {
 +        self.0 /= other.0;
 +    }
 +}
 +
 +impl DivAssign for Foo {
 +    fn div_assign(&mut self, other: Foo) {
 +        self.0 /= other.0; // OK: BinOpKind::Div == DivAssign
 +    }
 +}
 +
 +impl Mul for Foo {
 +    type Output = Foo;
 +
 +    fn mul(self, other: Foo) -> Foo {
 +        Foo(self.0 * other.0 % 42) // OK: BinOpKind::Rem part of BiExpr as parent node
 +    }
 +}
 +
 +impl Sub for Foo {
 +    type Output = Foo;
 +
 +    fn sub(self, other: Self) -> Self {
 +        Foo(self.0 * other.0 - 42) // OK: BinOpKind::Mul part of BiExpr as child node
 +    }
 +}
 +
 +impl Div for Foo {
 +    type Output = Foo;
 +
 +    fn div(self, other: Self) -> Self {
 +        Foo(do_nothing(self.0 + other.0) / 42) // OK: BinOpKind::Add part of BiExpr as child node
 +    }
 +}
 +
++impl Rem for Foo {
++    type Output = Foo;
++
++    fn rem(self, other: Self) -> Self {
++        Foo(self.0 / other.0)
++    }
++}
++
++impl BitAnd for Foo {
++    type Output = Foo;
++
++    fn bitand(self, other: Self) -> Self {
++        Foo(self.0 | other.0)
++    }
++}
++
++impl BitOr for Foo {
++    type Output = Foo;
++
++    fn bitor(self, other: Self) -> Self {
++        Foo(self.0 ^ other.0)
++    }
++}
++
++impl BitXor for Foo {
++    type Output = Foo;
++
++    fn bitxor(self, other: Self) -> Self {
++        Foo(self.0 & other.0)
++    }
++}
++
++impl Shl for Foo {
++    type Output = Foo;
++
++    fn shl(self, other: Self) -> Self {
++        Foo(self.0 >> other.0)
++    }
++}
++
++impl Shr for Foo {
++    type Output = Foo;
++
++    fn shr(self, other: Self) -> Self {
++        Foo(self.0 << other.0)
++    }
++}
++
 +struct Bar(i32);
 +
 +impl Add for Bar {
 +    type Output = Bar;
 +
 +    fn add(self, other: Self) -> Self {
 +        Bar(self.0 & !other.0) // OK: UnNot part of BiExpr as child node
 +    }
 +}
 +
 +impl Sub for Bar {
 +    type Output = Bar;
 +
 +    fn sub(self, other: Self) -> Self {
 +        if self.0 <= other.0 {
 +            Bar(-(self.0 & other.0)) // OK: UnNeg part of BiExpr as parent node
 +        } else {
 +            Bar(0)
 +        }
 +    }
 +}
 +
 +fn main() {}
 +
 +fn do_nothing(x: u32) -> u32 {
 +    x
 +}
 +
 +struct MultipleBinops(u32);
 +
 +impl Add for MultipleBinops {
 +    type Output = MultipleBinops;
 +
 +    // OK: multiple Binops in `add` impl
 +    fn add(self, other: Self) -> Self::Output {
 +        let mut result = self.0 + other.0;
 +        if result >= u32::max_value() {
 +            result -= u32::max_value();
 +        }
 +        MultipleBinops(result)
 +    }
 +}
 +
 +impl Mul for MultipleBinops {
 +    type Output = MultipleBinops;
 +
 +    // OK: multiple Binops in `mul` impl
 +    fn mul(self, other: Self) -> Self::Output {
 +        let mut result: u32 = 0;
 +        let size = std::cmp::max(self.0, other.0) as usize;
 +        let mut v = vec![0; size + 1];
 +        for i in 0..size + 1 {
 +            result *= i as u32;
 +        }
 +        MultipleBinops(result)
 +    }
 +}
index 23d47e3f1ff085b647451daa653918cf31093863,0000000000000000000000000000000000000000..388fc7400820947ab912c088099d94e20391995d
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,60 @@@
-   --> $DIR/suspicious_arithmetic_impl.rs:11:20
 +error: suspicious use of binary operator in `Add` impl
-   --> $DIR/suspicious_arithmetic_impl.rs:17:23
++  --> $DIR/suspicious_arithmetic_impl.rs:13:20
 +   |
 +LL |         Foo(self.0 - other.0)
 +   |                    ^
 +   |
 +   = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings`
 +
 +error: suspicious use of binary operator in `AddAssign` impl
-   --> $DIR/suspicious_arithmetic_impl.rs:30:16
++  --> $DIR/suspicious_arithmetic_impl.rs:19:23
 +   |
 +LL |         *self = *self - other;
 +   |                       ^
 +   |
 +   = note: `#[deny(clippy::suspicious_op_assign_impl)]` on by default
 +
 +error: suspicious use of binary operator in `MulAssign` impl
- error: aborting due to 3 previous errors
++  --> $DIR/suspicious_arithmetic_impl.rs:32:16
 +   |
 +LL |         self.0 /= other.0;
 +   |                ^^
 +
++error: suspicious use of binary operator in `Rem` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:70:20
++   |
++LL |         Foo(self.0 / other.0)
++   |                    ^
++
++error: suspicious use of binary operator in `BitAnd` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:78:20
++   |
++LL |         Foo(self.0 | other.0)
++   |                    ^
++
++error: suspicious use of binary operator in `BitOr` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:86:20
++   |
++LL |         Foo(self.0 ^ other.0)
++   |                    ^
++
++error: suspicious use of binary operator in `BitXor` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:94:20
++   |
++LL |         Foo(self.0 & other.0)
++   |                    ^
++
++error: suspicious use of binary operator in `Shl` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:102:20
++   |
++LL |         Foo(self.0 >> other.0)
++   |                    ^^
++
++error: suspicious use of binary operator in `Shr` impl
++  --> $DIR/suspicious_arithmetic_impl.rs:110:20
++   |
++LL |         Foo(self.0 << other.0)
++   |                    ^^
++
++error: aborting due to 9 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..eb8105c6b6da0f28a50ee521f4550e065a96de55
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,69 @@@
++#![warn(clippy::to_string_in_display)]
++#![allow(clippy::inherent_to_string_shadow_display)]
++
++use std::fmt;
++
++struct A;
++impl A {
++    fn fmt(&self) {
++        self.to_string();
++    }
++}
++
++trait B {
++    fn fmt(&self) {}
++}
++
++impl B for A {
++    fn fmt(&self) {
++        self.to_string();
++    }
++}
++
++impl fmt::Display for A {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        write!(f, "{}", self.to_string())
++    }
++}
++
++fn fmt(a: A) {
++    a.to_string();
++}
++
++struct C;
++
++impl C {
++    fn to_string(&self) -> String {
++        String::from("I am C")
++    }
++}
++
++impl fmt::Display for C {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        write!(f, "{}", self.to_string())
++    }
++}
++
++enum D {
++    E(String),
++    F,
++}
++
++impl std::fmt::Display for D {
++    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
++        match &self {
++            Self::E(string) => write!(f, "E {}", string.to_string()),
++            Self::F => write!(f, "F"),
++        }
++    }
++}
++
++fn main() {
++    let a = A;
++    a.to_string();
++    a.fmt();
++    fmt(a);
++
++    let c = C;
++    c.to_string();
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5f26ef413e239f331c60305fcab910173752b5ee
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++error: using `to_string` in `fmt::Display` implementation might lead to infinite recursion
++  --> $DIR/to_string_in_display.rs:25:25
++   |
++LL |         write!(f, "{}", self.to_string())
++   |                         ^^^^^^^^^^^^^^^^
++   |
++   = note: `-D clippy::to-string-in-display` implied by `-D warnings`
++
++error: aborting due to previous error
++
index bb853d237047fbc33f6bd85b50c04ad8f2e5edf2,0000000000000000000000000000000000000000..9f1948359e7d585d6d8ca2eacd26022d7330eeb8
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,112 @@@
- fn int_to_float() {
-     let _: f32 = unsafe { std::mem::transmute(0_u32) };
-     let _: f32 = unsafe { std::mem::transmute(0_i32) };
++#![feature(const_fn_transmute)]
 +#![allow(dead_code)]
 +
 +extern crate core;
 +
 +use std::mem::transmute as my_transmute;
 +use std::vec::Vec as MyVec;
 +
 +fn my_int() -> Usize {
 +    Usize(42)
 +}
 +
 +fn my_vec() -> MyVec<i32> {
 +    vec![]
 +}
 +
 +#[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
 +#[warn(clippy::useless_transmute)]
 +unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
 +    let _: &'a T = core::intrinsics::transmute(t);
 +
 +    let _: &'a U = core::intrinsics::transmute(t);
 +
 +    let _: *const T = core::intrinsics::transmute(t);
 +
 +    let _: *mut T = core::intrinsics::transmute(t);
 +
 +    let _: *const U = core::intrinsics::transmute(t);
 +}
 +
 +#[warn(clippy::useless_transmute)]
 +fn useless() {
 +    unsafe {
 +        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
 +
 +        let _: Vec<i32> = core::mem::transmute(my_vec());
 +
 +        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
 +
 +        let _: Vec<i32> = std::mem::transmute(my_vec());
 +
 +        let _: Vec<i32> = my_transmute(my_vec());
 +
 +        let _: *const usize = std::mem::transmute(5_isize);
 +
 +        let _ = 5_isize as *const usize;
 +
 +        let _: *const usize = std::mem::transmute(1 + 1usize);
 +
 +        let _ = (1 + 1_usize) as *const usize;
 +    }
 +}
 +
 +struct Usize(usize);
 +
 +#[warn(clippy::crosspointer_transmute)]
 +fn crosspointer() {
 +    let mut int: Usize = Usize(0);
 +    let int_const_ptr: *const Usize = &int as *const Usize;
 +    let int_mut_ptr: *mut Usize = &mut int as *mut Usize;
 +
 +    unsafe {
 +        let _: Usize = core::intrinsics::transmute(int_const_ptr);
 +
 +        let _: Usize = core::intrinsics::transmute(int_mut_ptr);
 +
 +        let _: *const Usize = core::intrinsics::transmute(my_int());
 +
 +        let _: *mut Usize = core::intrinsics::transmute(my_int());
 +    }
 +}
 +
 +#[warn(clippy::transmute_int_to_char)]
 +fn int_to_char() {
 +    let _: char = unsafe { std::mem::transmute(0_u32) };
 +    let _: char = unsafe { std::mem::transmute(0_i32) };
 +}
 +
 +#[warn(clippy::transmute_int_to_bool)]
 +fn int_to_bool() {
 +    let _: bool = unsafe { std::mem::transmute(0_u8) };
 +}
 +
 +#[warn(clippy::transmute_int_to_float)]
++mod int_to_float {
++    fn test() {
++        let _: f32 = unsafe { std::mem::transmute(0_u32) };
++        let _: f32 = unsafe { std::mem::transmute(0_i32) };
++        let _: f64 = unsafe { std::mem::transmute(0_u64) };
++        let _: f64 = unsafe { std::mem::transmute(0_i64) };
++    }
++
++    mod issue_5747 {
++        const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
++        const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
++
++        const fn from_bits_32(v: i32) -> f32 {
++            unsafe { std::mem::transmute(v) }
++        }
++
++        const fn from_bits_64(v: u64) -> f64 {
++            unsafe { std::mem::transmute(v) }
++        }
++    }
 +}
 +
 +fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
 +    let _: &str = unsafe { std::mem::transmute(b) };
 +    let _: &mut str = unsafe { std::mem::transmute(mb) };
 +}
 +
 +fn main() {}
index 8582080498f3e4febde7b3ef68d942c6a8eaf3bd,0000000000000000000000000000000000000000..ad9953d12bcc626fb93c7849d0e8b6957406c76b
mode 100644,000000..100644
--- /dev/null
@@@ -1,146 -1,0 +1,158 @@@
-   --> $DIR/transmute.rs:19:20
 +error: transmute from a type (`&T`) to itself
-   --> $DIR/transmute.rs:23:23
++  --> $DIR/transmute.rs:20:20
 +   |
 +LL |     let _: &'a T = core::intrinsics::transmute(t);
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::useless-transmute` implied by `-D warnings`
 +
 +error: transmute from a reference to a pointer
-   --> $DIR/transmute.rs:25:21
++  --> $DIR/transmute.rs:24:23
 +   |
 +LL |     let _: *const T = core::intrinsics::transmute(t);
 +   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
 +
 +error: transmute from a reference to a pointer
-   --> $DIR/transmute.rs:27:23
++  --> $DIR/transmute.rs:26:21
 +   |
 +LL |     let _: *mut T = core::intrinsics::transmute(t);
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 +
 +error: transmute from a reference to a pointer
-   --> $DIR/transmute.rs:33:27
++  --> $DIR/transmute.rs:28:23
 +   |
 +LL |     let _: *const U = core::intrinsics::transmute(t);
 +   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
-   --> $DIR/transmute.rs:35:27
++  --> $DIR/transmute.rs:34:27
 +   |
 +LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
-   --> $DIR/transmute.rs:37:27
++  --> $DIR/transmute.rs:36:27
 +   |
 +LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
-   --> $DIR/transmute.rs:39:27
++  --> $DIR/transmute.rs:38:27
 +   |
 +LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
-   --> $DIR/transmute.rs:41:27
++  --> $DIR/transmute.rs:40:27
 +   |
 +LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
-   --> $DIR/transmute.rs:43:31
++  --> $DIR/transmute.rs:42:27
 +   |
 +LL |         let _: Vec<i32> = my_transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from an integer to a pointer
-   --> $DIR/transmute.rs:47:31
++  --> $DIR/transmute.rs:44:31
 +   |
 +LL |         let _: *const usize = std::mem::transmute(5_isize);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 +
 +error: transmute from an integer to a pointer
-   --> $DIR/transmute.rs:62:24
++  --> $DIR/transmute.rs:48:31
 +   |
 +LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 +
 +error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-   --> $DIR/transmute.rs:64:24
++  --> $DIR/transmute.rs:63:24
 +   |
 +LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 +
 +error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-   --> $DIR/transmute.rs:66:31
++  --> $DIR/transmute.rs:65:24
 +   |
 +LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-   --> $DIR/transmute.rs:68:29
++  --> $DIR/transmute.rs:67:31
 +   |
 +LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-   --> $DIR/transmute.rs:74:28
++  --> $DIR/transmute.rs:69:29
 +   |
 +LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
 +   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a `u32` to a `char`
-   --> $DIR/transmute.rs:75:28
++  --> $DIR/transmute.rs:75:28
 +   |
 +LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
 +   |
 +   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
 +
 +error: transmute from a `i32` to a `char`
-   --> $DIR/transmute.rs:80:28
++  --> $DIR/transmute.rs:76:28
 +   |
 +LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
 +
 +error: transmute from a `u8` to a `bool`
-   --> $DIR/transmute.rs:85:27
++  --> $DIR/transmute.rs:81:28
 +   |
 +LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
 +   |
 +   = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
 +
 +error: transmute from a `u32` to a `f32`
- LL |     let _: f32 = unsafe { std::mem::transmute(0_u32) };
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
++  --> $DIR/transmute.rs:87:31
 +   |
-   --> $DIR/transmute.rs:86:27
++LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
 +   |
 +   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
 +
 +error: transmute from a `i32` to a `f32`
- LL |     let _: f32 = unsafe { std::mem::transmute(0_i32) };
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
++  --> $DIR/transmute.rs:88:31
++   |
++LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
++
++error: transmute from a `u64` to a `f64`
++  --> $DIR/transmute.rs:89:31
++   |
++LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
++
++error: transmute from a `i64` to a `f64`
++  --> $DIR/transmute.rs:90:31
 +   |
-   --> $DIR/transmute.rs:90:28
++LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 +
 +error: transmute from a `&[u8]` to a `&str`
-   --> $DIR/transmute.rs:91:32
++  --> $DIR/transmute.rs:108:28
 +   |
 +LL |     let _: &str = unsafe { std::mem::transmute(b) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
 +   |
 +   = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 +
 +error: transmute from a `&mut [u8]` to a `&mut str`
- error: aborting due to 22 previous errors
++  --> $DIR/transmute.rs:109:32
 +   |
 +LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
 +   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 +
++error: aborting due to 24 previous errors
 +
index ce942751ada82cee06778cf4599528b3073e5397,0000000000000000000000000000000000000000..1040fee4b34d00c3b2cff7c9106ac16338d8ade7
mode 100644,000000..100644
--- /dev/null
@@@ -1,12 -1,0 +1,26 @@@
- #[warn(clippy::transmute_float_to_int)]
++#![feature(const_fn_transmute)]
++#![warn(clippy::transmute_float_to_int)]
 +
 +fn float_to_int() {
 +    let _: u32 = unsafe { std::mem::transmute(1f32) };
 +    let _: i32 = unsafe { std::mem::transmute(1f32) };
 +    let _: u64 = unsafe { std::mem::transmute(1f64) };
 +    let _: i64 = unsafe { std::mem::transmute(1f64) };
 +    let _: u64 = unsafe { std::mem::transmute(1.0) };
 +    let _: u64 = unsafe { std::mem::transmute(-1.0) };
 +}
 +
++mod issue_5747 {
++    const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
++    const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
++
++    const fn to_bits_32(v: f32) -> u32 {
++        unsafe { std::mem::transmute(v) }
++    }
++
++    const fn to_bits_64(v: f64) -> i64 {
++        unsafe { std::mem::transmute(v) }
++    }
++}
++
 +fn main() {}
index eb786bb39f95aa5c1f7110d053acf78cd96b340b,0000000000000000000000000000000000000000..5a40cf381d6147ee464da4cdcbe0e72ab1e75721
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
-   --> $DIR/transmute_float_to_int.rs:4:27
 +error: transmute from a `f32` to a `u32`
-   --> $DIR/transmute_float_to_int.rs:5:27
++  --> $DIR/transmute_float_to_int.rs:5:27
 +   |
 +LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
 +   |
 +   = note: `-D clippy::transmute-float-to-int` implied by `-D warnings`
 +
 +error: transmute from a `f32` to a `i32`
-   --> $DIR/transmute_float_to_int.rs:6:27
++  --> $DIR/transmute_float_to_int.rs:6:27
 +   |
 +LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
 +
 +error: transmute from a `f64` to a `u64`
-   --> $DIR/transmute_float_to_int.rs:7:27
++  --> $DIR/transmute_float_to_int.rs:7:27
 +   |
 +LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
 +
 +error: transmute from a `f64` to a `i64`
-   --> $DIR/transmute_float_to_int.rs:8:27
++  --> $DIR/transmute_float_to_int.rs:8:27
 +   |
 +LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
 +
 +error: transmute from a `f64` to a `u64`
-   --> $DIR/transmute_float_to_int.rs:9:27
++  --> $DIR/transmute_float_to_int.rs:9:27
 +   |
 +LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
 +
 +error: transmute from a `f64` to a `u64`
++  --> $DIR/transmute_float_to_int.rs:10:27
 +   |
 +LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
 +
 +error: aborting due to 6 previous errors
 +
index 316426f1cf181788dbc48dba7e69f244f4908531,0000000000000000000000000000000000000000..e7e0a31febc45919ca44408c7772a83cc162126c
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,132 @@@
 +// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)"
 +// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
 +
 +#![deny(clippy::trivially_copy_pass_by_ref)]
 +#![allow(
 +    clippy::many_single_char_names,
 +    clippy::blacklisted_name,
 +    clippy::redundant_field_names
 +)]
 +
 +#[derive(Copy, Clone)]
 +struct Foo(u32);
 +
 +#[derive(Copy, Clone)]
 +struct Bar([u8; 24]);
 +
 +#[derive(Copy, Clone)]
 +pub struct Color {
 +    pub r: u8,
 +    pub g: u8,
 +    pub b: u8,
 +    pub a: u8,
 +}
 +
 +struct FooRef<'a> {
 +    foo: &'a Foo,
 +}
 +
 +type Baz = u32;
 +
 +fn good(a: &mut u32, b: u32, c: &Bar) {}
 +
 +fn good_return_implicit_lt_ref(foo: &Foo) -> &u32 {
 +    &foo.0
 +}
 +
 +#[allow(clippy::needless_lifetimes)]
 +fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
 +    &foo.0
 +}
 +
 +fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
 +    FooRef { foo }
 +}
 +
 +#[allow(clippy::needless_lifetimes)]
 +fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> {
 +    FooRef { foo }
 +}
 +
 +fn bad(x: &u32, y: &Foo, z: &Baz) {}
 +
 +impl Foo {
 +    fn good(self, a: &mut u32, b: u32, c: &Bar) {}
 +
 +    fn good2(&mut self) {}
 +
 +    fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 +
 +    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +}
 +
 +impl AsRef<u32> for Foo {
 +    fn as_ref(&self) -> &u32 {
 +        &self.0
 +    }
 +}
 +
 +impl Bar {
 +    fn good(&self, a: &mut u32, b: u32, c: &Bar) {}
 +
 +    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +}
 +
 +trait MyTrait {
 +    fn trait_method(&self, _foo: &Foo);
 +}
 +
 +pub trait MyTrait2 {
 +    fn trait_method2(&self, _color: &Color);
 +}
 +
 +impl MyTrait for Foo {
 +    fn trait_method(&self, _foo: &Foo) {
 +        unimplemented!()
 +    }
 +}
 +
 +#[allow(unused_variables)]
 +mod issue3992 {
 +    pub trait A {
 +        #[allow(clippy::trivially_copy_pass_by_ref)]
 +        fn a(b: &u16) {}
 +    }
 +
 +    #[allow(clippy::trivially_copy_pass_by_ref)]
 +    pub fn c(d: &u16) {}
 +}
 +
++mod issue5876 {
++    // Don't lint here as it is always inlined
++    #[inline(always)]
++    fn foo_always(x: &i32) {
++        println!("{}", x);
++    }
++
++    #[inline(never)]
++    fn foo_never(x: &i32) {
++        println!("{}", x);
++    }
++
++    #[inline]
++    fn foo(x: &i32) {
++        println!("{}", x);
++    }
++}
++
 +fn main() {
 +    let (mut foo, bar) = (Foo(0), Bar([0; 24]));
 +    let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0);
 +    good(&mut a, b, &c);
 +    good_return_implicit_lt_ref(&y);
 +    good_return_explicit_lt_ref(&y);
 +    bad(&x, &y, &z);
 +    foo.good(&mut a, b, &c);
 +    foo.good2();
 +    foo.bad(&x, &y, &z);
 +    Foo::bad2(&x, &y, &z);
 +    bar.good(&mut a, b, &c);
 +    Bar::bad2(&x, &y, &z);
 +    foo.as_ref();
 +}
index be0914e4a7947f7197002ee591009b0c79fa8abd,0000000000000000000000000000000000000000..ccc3cdb2b74264fec42b9741312f627315ee906b
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,110 @@@
- error: aborting due to 15 previous errors
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:51:11
 +   |
 +LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
 +   |           ^^^^ help: consider passing by value instead: `u32`
 +   |
 +note: the lint level is defined here
 +  --> $DIR/trivially_copy_pass_by_ref.rs:4:9
 +   |
 +LL | #![deny(clippy::trivially_copy_pass_by_ref)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:51:20
 +   |
 +LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
 +   |                    ^^^^ help: consider passing by value instead: `Foo`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:51:29
 +   |
 +LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
 +   |                             ^^^^ help: consider passing by value instead: `Baz`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:58:12
 +   |
 +LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 +   |            ^^^^^ help: consider passing by value instead: `self`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:58:22
 +   |
 +LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 +   |                      ^^^^ help: consider passing by value instead: `u32`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:58:31
 +   |
 +LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 +   |                               ^^^^ help: consider passing by value instead: `Foo`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:58:40
 +   |
 +LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 +   |                                        ^^^^ help: consider passing by value instead: `Baz`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:60:16
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                ^^^^ help: consider passing by value instead: `u32`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:60:25
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                         ^^^^ help: consider passing by value instead: `Foo`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:60:34
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                                  ^^^^ help: consider passing by value instead: `Baz`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:72:16
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                ^^^^ help: consider passing by value instead: `u32`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:72:25
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                         ^^^^ help: consider passing by value instead: `Foo`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:72:34
 +   |
 +LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 +   |                                  ^^^^ help: consider passing by value instead: `Baz`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:76:34
 +   |
 +LL |     fn trait_method(&self, _foo: &Foo);
 +   |                                  ^^^^ help: consider passing by value instead: `Foo`
 +
 +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
 +  --> $DIR/trivially_copy_pass_by_ref.rs:80:37
 +   |
 +LL |     fn trait_method2(&self, _color: &Color);
 +   |                                     ^^^^^^ help: consider passing by value instead: `Color`
 +
++error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
++  --> $DIR/trivially_copy_pass_by_ref.rs:108:21
++   |
++LL |     fn foo_never(x: &i32) {
++   |                     ^^^^ help: consider passing by value instead: `i32`
++
++error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
++  --> $DIR/trivially_copy_pass_by_ref.rs:113:15
++   |
++LL |     fn foo(x: &i32) {
++   |               ^^^^ help: consider passing by value instead: `i32`
++
++error: aborting due to 17 previous errors
 +
index 2c9d4d39e6c7d9e7d18c8c7daf59fbe075b18b32,0000000000000000000000000000000000000000..e785ac02feb320e4c4fb1c54e671a335a4a3d3fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,92 -1,0 +1,110 @@@
 +// does not test any rustfixable lints
 +
 +#![warn(clippy::clone_on_ref_ptr)]
 +#![allow(unused, clippy::redundant_clone)]
 +
 +use std::cell::RefCell;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +trait SomeTrait {}
 +struct SomeImpl;
 +impl SomeTrait for SomeImpl {}
 +
 +fn main() {}
 +
 +fn clone_on_ref_ptr() {
 +    let rc = Rc::new(true);
 +    let arc = Arc::new(true);
 +
 +    let rcweak = Rc::downgrade(&rc);
 +    let arc_weak = Arc::downgrade(&arc);
 +
 +    rc.clone();
 +    Rc::clone(&rc);
 +
 +    arc.clone();
 +    Arc::clone(&arc);
 +
 +    rcweak.clone();
 +    rc::Weak::clone(&rcweak);
 +
 +    arc_weak.clone();
 +    sync::Weak::clone(&arc_weak);
 +
 +    let x = Arc::new(SomeImpl);
 +    let _: Arc<dyn SomeTrait> = x.clone();
 +}
 +
 +fn clone_on_copy_generic<T: Copy>(t: T) {
 +    t.clone();
 +
 +    Some(t).clone();
 +}
 +
 +fn clone_on_double_ref() {
 +    let x = vec![1];
 +    let y = &&x;
 +    let z: &Vec<_> = y.clone();
 +
 +    println!("{:p} {:p}", *y, z);
 +}
 +
 +mod many_derefs {
 +    struct A;
 +    struct B;
 +    struct C;
 +    struct D;
 +    #[derive(Copy, Clone)]
 +    struct E;
 +
 +    macro_rules! impl_deref {
 +        ($src:ident, $dst:ident) => {
 +            impl std::ops::Deref for $src {
 +                type Target = $dst;
 +                fn deref(&self) -> &Self::Target {
 +                    &$dst
 +                }
 +            }
 +        };
 +    }
 +
 +    impl_deref!(A, B);
 +    impl_deref!(B, C);
 +    impl_deref!(C, D);
 +    impl std::ops::Deref for D {
 +        type Target = &'static E;
 +        fn deref(&self) -> &Self::Target {
 +            &&E
 +        }
 +    }
 +
 +    fn go1() {
 +        let a = A;
 +        let _: E = a.clone();
 +        let _: E = *****a;
 +    }
 +
 +    fn check(mut encoded: &[u8]) {
 +        let _ = &mut encoded.clone();
 +        let _ = &encoded.clone();
 +    }
 +}
++
++mod issue2076 {
++    use std::rc::Rc;
++
++    macro_rules! try_opt {
++        ($expr: expr) => {
++            match $expr {
++                Some(value) => value,
++                None => return None,
++            }
++        };
++    }
++
++    fn func() -> Option<Rc<u8>> {
++        let rc = Rc::new(42);
++        Some(try_opt!(Some(rc)).clone())
++    }
++}
index 113fab6900954c891b2610517dd728148aa3994b,0000000000000000000000000000000000000000..5ffa6c4fd06167ce0c7e68545fef718f97c00418
mode 100644,000000..100644
--- /dev/null
@@@ -1,100 -1,0 +1,106 @@@
- error: aborting due to 11 previous errors
 +error: using `.clone()` on a ref-counted pointer
 +  --> $DIR/unnecessary_clone.rs:23:5
 +   |
 +LL |     rc.clone();
 +   |     ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
 +   |
 +   = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
 +
 +error: using `.clone()` on a ref-counted pointer
 +  --> $DIR/unnecessary_clone.rs:26:5
 +   |
 +LL |     arc.clone();
 +   |     ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
 +
 +error: using `.clone()` on a ref-counted pointer
 +  --> $DIR/unnecessary_clone.rs:29:5
 +   |
 +LL |     rcweak.clone();
 +   |     ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
 +
 +error: using `.clone()` on a ref-counted pointer
 +  --> $DIR/unnecessary_clone.rs:32:5
 +   |
 +LL |     arc_weak.clone();
 +   |     ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
 +
 +error: using `.clone()` on a ref-counted pointer
 +  --> $DIR/unnecessary_clone.rs:36:33
 +   |
 +LL |     let _: Arc<dyn SomeTrait> = x.clone();
 +   |                                 ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
 +
 +error: using `clone` on a `Copy` type
 +  --> $DIR/unnecessary_clone.rs:40:5
 +   |
 +LL |     t.clone();
 +   |     ^^^^^^^^^ help: try removing the `clone` call: `t`
 +   |
 +   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 +
 +error: using `clone` on a `Copy` type
 +  --> $DIR/unnecessary_clone.rs:42:5
 +   |
 +LL |     Some(t).clone();
 +   |     ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
 +
 +error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
 +  --> $DIR/unnecessary_clone.rs:48:22
 +   |
 +LL |     let z: &Vec<_> = y.clone();
 +   |                      ^^^^^^^^^
 +   |
 +   = note: `#[deny(clippy::clone_double_ref)]` on by default
 +help: try dereferencing it
 +   |
 +LL |     let z: &Vec<_> = &(*y).clone();
 +   |                      ^^^^^^^^^^^^^
 +help: or try being explicit if you are sure, that you want to clone a reference
 +   |
 +LL |     let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: using `clone` on a `Copy` type
 +  --> $DIR/unnecessary_clone.rs:84:20
 +   |
 +LL |         let _: E = a.clone();
 +   |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
 +
 +error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
 +  --> $DIR/unnecessary_clone.rs:89:22
 +   |
 +LL |         let _ = &mut encoded.clone();
 +   |                      ^^^^^^^^^^^^^^^
 +   |
 +help: try dereferencing it
 +   |
 +LL |         let _ = &mut &(*encoded).clone();
 +   |                      ^^^^^^^^^^^^^^^^^^^
 +help: or try being explicit if you are sure, that you want to clone a reference
 +   |
 +LL |         let _ = &mut <&[u8]>::clone(encoded);
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
 +  --> $DIR/unnecessary_clone.rs:90:18
 +   |
 +LL |         let _ = &encoded.clone();
 +   |                  ^^^^^^^^^^^^^^^
 +   |
 +help: try dereferencing it
 +   |
 +LL |         let _ = &&(*encoded).clone();
 +   |                  ^^^^^^^^^^^^^^^^^^^
 +help: or try being explicit if you are sure, that you want to clone a reference
 +   |
 +LL |         let _ = &<&[u8]>::clone(encoded);
 +   |                  ^^^^^^^^^^^^^^^^^^^^^^^
 +
++error: using `.clone()` on a ref-counted pointer
++  --> $DIR/unnecessary_clone.rs:108:14
++   |
++LL |         Some(try_opt!(Some(rc)).clone())
++   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::<u8>::clone(&try_opt!(Some(rc)))`
++
++error: aborting due to 12 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fa66e68794e4be0d6b1ac082c2c9b2044b0e36bb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,117 @@@
++// run-rustfix
++#![warn(clippy::unnecessary_lazy_evaluations)]
++#![allow(clippy::redundant_closure)]
++#![allow(clippy::bind_instead_of_map)]
++
++struct Deep(Option<usize>);
++
++#[derive(Copy, Clone)]
++struct SomeStruct {
++    some_field: usize,
++}
++
++impl SomeStruct {
++    fn return_some_field(&self) -> usize {
++        self.some_field
++    }
++}
++
++fn some_call<T: Default>() -> T {
++    T::default()
++}
++
++fn main() {
++    let astronomers_pi = 10;
++    let ext_arr: [usize; 1] = [2];
++    let ext_str = SomeStruct { some_field: 10 };
++
++    let mut opt = Some(42);
++    let ext_opt = Some(42);
++    let nested_opt = Some(Some(42));
++    let nested_tuple_opt = Some(Some((42, 43)));
++
++    // Should lint - Option
++    let _ = opt.unwrap_or(2);
++    let _ = opt.unwrap_or(astronomers_pi);
++    let _ = opt.unwrap_or(ext_str.some_field);
++    let _ = opt.unwrap_or(ext_arr[0]);
++    let _ = opt.and(ext_opt);
++    let _ = opt.or(ext_opt);
++    let _ = opt.or(None);
++    let _ = opt.get_or_insert(2);
++    let _ = opt.ok_or(2);
++    let _ = opt.ok_or(ext_arr[0]);
++
++    // Cases when unwrap is not called on a simple variable
++    let _ = Some(10).unwrap_or(2);
++    let _ = Some(10).and(ext_opt);
++    let _: Option<usize> = None.or(ext_opt);
++    let _ = None.get_or_insert(2);
++    let _: Result<usize, usize> = None.ok_or(2);
++    let _: Option<usize> = None.or(None);
++
++    let mut deep = Deep(Some(42));
++    let _ = deep.0.unwrap_or(2);
++    let _ = deep.0.and(ext_opt);
++    let _ = deep.0.or(None);
++    let _ = deep.0.get_or_insert(2);
++    let _ = deep.0.ok_or(2);
++
++    // Should not lint - Option
++    let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
++    let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
++    let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
++    let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
++    let _ = opt.or_else(some_call);
++    let _ = opt.or_else(|| some_call());
++    let _: Result<usize, usize> = opt.ok_or_else(|| some_call());
++    let _: Result<usize, usize> = opt.ok_or_else(some_call);
++    let _ = deep.0.get_or_insert_with(|| some_call());
++    let _ = deep.0.or_else(some_call);
++    let _ = deep.0.or_else(|| some_call());
++
++    // These are handled by bind_instead_of_map
++    let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
++    let _ = Some(10).and_then(|idx| Some(idx));
++    let _: Option<usize> = None.or_else(|| Some(3));
++    let _ = deep.0.or_else(|| Some(3));
++    let _ = opt.or_else(|| Some(3));
++
++    // Should lint - Result
++    let res: Result<usize, usize> = Err(5);
++    let res2: Result<usize, SomeStruct> = Err(SomeStruct { some_field: 5 });
++
++    let _ = res2.unwrap_or(2);
++    let _ = res2.unwrap_or(astronomers_pi);
++    let _ = res2.unwrap_or(ext_str.some_field);
++
++    // Should not lint - Result
++    let _ = res.unwrap_or_else(|err| err);
++    let _ = res.unwrap_or_else(|err| ext_arr[err]);
++    let _ = res2.unwrap_or_else(|err| err.some_field);
++    let _ = res2.unwrap_or_else(|err| err.return_some_field());
++    let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
++
++    let _: Result<usize, usize> = res.and_then(|x| Ok(x));
++    let _: Result<usize, usize> = res.and_then(|x| Err(x));
++
++    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
++    let _: Result<usize, usize> = res.or_else(|err| Err(err));
++
++    // These are handled by bind_instead_of_map
++    let _: Result<usize, usize> = res.and_then(|_| Ok(2));
++    let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
++    let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.and_then(|_| Err(2));
++    let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
++    let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.or_else(|_| Ok(2));
++    let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
++    let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.or_else(|_| Err(2));
++    let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
++    let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..04f47d1aa2978f8afb54126b6d2cd97532f20521
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,117 @@@
++// run-rustfix
++#![warn(clippy::unnecessary_lazy_evaluations)]
++#![allow(clippy::redundant_closure)]
++#![allow(clippy::bind_instead_of_map)]
++
++struct Deep(Option<usize>);
++
++#[derive(Copy, Clone)]
++struct SomeStruct {
++    some_field: usize,
++}
++
++impl SomeStruct {
++    fn return_some_field(&self) -> usize {
++        self.some_field
++    }
++}
++
++fn some_call<T: Default>() -> T {
++    T::default()
++}
++
++fn main() {
++    let astronomers_pi = 10;
++    let ext_arr: [usize; 1] = [2];
++    let ext_str = SomeStruct { some_field: 10 };
++
++    let mut opt = Some(42);
++    let ext_opt = Some(42);
++    let nested_opt = Some(Some(42));
++    let nested_tuple_opt = Some(Some((42, 43)));
++
++    // Should lint - Option
++    let _ = opt.unwrap_or_else(|| 2);
++    let _ = opt.unwrap_or_else(|| astronomers_pi);
++    let _ = opt.unwrap_or_else(|| ext_str.some_field);
++    let _ = opt.unwrap_or_else(|| ext_arr[0]);
++    let _ = opt.and_then(|_| ext_opt);
++    let _ = opt.or_else(|| ext_opt);
++    let _ = opt.or_else(|| None);
++    let _ = opt.get_or_insert_with(|| 2);
++    let _ = opt.ok_or_else(|| 2);
++    let _ = opt.ok_or_else(|| ext_arr[0]);
++
++    // Cases when unwrap is not called on a simple variable
++    let _ = Some(10).unwrap_or_else(|| 2);
++    let _ = Some(10).and_then(|_| ext_opt);
++    let _: Option<usize> = None.or_else(|| ext_opt);
++    let _ = None.get_or_insert_with(|| 2);
++    let _: Result<usize, usize> = None.ok_or_else(|| 2);
++    let _: Option<usize> = None.or_else(|| None);
++
++    let mut deep = Deep(Some(42));
++    let _ = deep.0.unwrap_or_else(|| 2);
++    let _ = deep.0.and_then(|_| ext_opt);
++    let _ = deep.0.or_else(|| None);
++    let _ = deep.0.get_or_insert_with(|| 2);
++    let _ = deep.0.ok_or_else(|| 2);
++
++    // Should not lint - Option
++    let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
++    let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
++    let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
++    let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
++    let _ = opt.or_else(some_call);
++    let _ = opt.or_else(|| some_call());
++    let _: Result<usize, usize> = opt.ok_or_else(|| some_call());
++    let _: Result<usize, usize> = opt.ok_or_else(some_call);
++    let _ = deep.0.get_or_insert_with(|| some_call());
++    let _ = deep.0.or_else(some_call);
++    let _ = deep.0.or_else(|| some_call());
++
++    // These are handled by bind_instead_of_map
++    let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
++    let _ = Some(10).and_then(|idx| Some(idx));
++    let _: Option<usize> = None.or_else(|| Some(3));
++    let _ = deep.0.or_else(|| Some(3));
++    let _ = opt.or_else(|| Some(3));
++
++    // Should lint - Result
++    let res: Result<usize, usize> = Err(5);
++    let res2: Result<usize, SomeStruct> = Err(SomeStruct { some_field: 5 });
++
++    let _ = res2.unwrap_or_else(|_| 2);
++    let _ = res2.unwrap_or_else(|_| astronomers_pi);
++    let _ = res2.unwrap_or_else(|_| ext_str.some_field);
++
++    // Should not lint - Result
++    let _ = res.unwrap_or_else(|err| err);
++    let _ = res.unwrap_or_else(|err| ext_arr[err]);
++    let _ = res2.unwrap_or_else(|err| err.some_field);
++    let _ = res2.unwrap_or_else(|err| err.return_some_field());
++    let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
++
++    let _: Result<usize, usize> = res.and_then(|x| Ok(x));
++    let _: Result<usize, usize> = res.and_then(|x| Err(x));
++
++    let _: Result<usize, usize> = res.or_else(|err| Ok(err));
++    let _: Result<usize, usize> = res.or_else(|err| Err(err));
++
++    // These are handled by bind_instead_of_map
++    let _: Result<usize, usize> = res.and_then(|_| Ok(2));
++    let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
++    let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.and_then(|_| Err(2));
++    let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
++    let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.or_else(|_| Ok(2));
++    let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
++    let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
++
++    let _: Result<usize, usize> = res.or_else(|_| Err(2));
++    let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
++    let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5c1b2eb1f14e833bd7aecb01e58c78a7699641da
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,148 @@@
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:34:13
++   |
++LL |     let _ = opt.unwrap_or_else(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)`
++   |
++   = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:35:13
++   |
++LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:36:13
++   |
++LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:37:13
++   |
++LL |     let _ = opt.unwrap_or_else(|| ext_arr[0]);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:38:13
++   |
++LL |     let _ = opt.and_then(|_| ext_opt);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:39:13
++   |
++LL |     let _ = opt.or_else(|| ext_opt);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:40:13
++   |
++LL |     let _ = opt.or_else(|| None);
++   |             ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:41:13
++   |
++LL |     let _ = opt.get_or_insert_with(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:42:13
++   |
++LL |     let _ = opt.ok_or_else(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:43:13
++   |
++LL |     let _ = opt.ok_or_else(|| ext_arr[0]);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:46:13
++   |
++LL |     let _ = Some(10).unwrap_or_else(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:47:13
++   |
++LL |     let _ = Some(10).and_then(|_| ext_opt);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:48:28
++   |
++LL |     let _: Option<usize> = None.or_else(|| ext_opt);
++   |                            ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:49:13
++   |
++LL |     let _ = None.get_or_insert_with(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:50:35
++   |
++LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
++   |                                   ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:51:28
++   |
++LL |     let _: Option<usize> = None.or_else(|| None);
++   |                            ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:54:13
++   |
++LL |     let _ = deep.0.unwrap_or_else(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:55:13
++   |
++LL |     let _ = deep.0.and_then(|_| ext_opt);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:56:13
++   |
++LL |     let _ = deep.0.or_else(|| None);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:57:13
++   |
++LL |     let _ = deep.0.get_or_insert_with(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)`
++
++error: unnecessary closure used to substitute value for `Option::None`
++  --> $DIR/unnecessary_lazy_eval.rs:58:13
++   |
++LL |     let _ = deep.0.ok_or_else(|| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)`
++
++error: unnecessary closure used to substitute value for `Result::Err`
++  --> $DIR/unnecessary_lazy_eval.rs:84:13
++   |
++LL |     let _ = res2.unwrap_or_else(|_| 2);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)`
++
++error: unnecessary closure used to substitute value for `Result::Err`
++  --> $DIR/unnecessary_lazy_eval.rs:85:13
++   |
++LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)`
++
++error: unnecessary closure used to substitute value for `Result::Err`
++  --> $DIR/unnecessary_lazy_eval.rs:86:13
++   |
++LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)`
++
++error: aborting due to 24 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2aa842adc85609690dfbc6f09875fb4b5541f338
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,44 @@@
++#![warn(clippy::unwrap_in_result)]
++
++struct A;
++
++impl A {
++    // should not be detected
++    fn good_divisible_by_3(i_str: String) -> Result<bool, String> {
++        // checks whether a string represents a number divisible by 3
++        let i_result = i_str.parse::<i32>();
++        match i_result {
++            Err(_e) => Err("Not a number".to_string()),
++            Ok(i) => {
++                if i % 3 == 0 {
++                    return Ok(true);
++                }
++                Err("Number is not divisible by 3".to_string())
++            },
++        }
++    }
++
++    // should be detected
++    fn bad_divisible_by_3(i_str: String) -> Result<bool, String> {
++        // checks whether a string represents a number divisible by 3
++        let i = i_str.parse::<i32>().unwrap();
++        if i % 3 == 0 {
++            Ok(true)
++        } else {
++            Err("Number is not divisible by 3".to_string())
++        }
++    }
++
++    fn example_option_expect(i_str: String) -> Option<bool> {
++        let i = i_str.parse::<i32>().expect("not a number");
++        if i % 3 == 0 {
++            return Some(true);
++        }
++        None
++    }
++}
++
++fn main() {
++    A::bad_divisible_by_3("3".to_string());
++    A::good_divisible_by_3("3".to_string());
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..56bc2f2d1c00edfe1665a9b532e2edd4ab299d7c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,41 @@@
++error: used unwrap or expect in a function that returns result or option
++  --> $DIR/unwrap_in_result.rs:22:5
++   |
++LL | /     fn bad_divisible_by_3(i_str: String) -> Result<bool, String> {
++LL | |         // checks whether a string represents a number divisible by 3
++LL | |         let i = i_str.parse::<i32>().unwrap();
++LL | |         if i % 3 == 0 {
++...  |
++LL | |         }
++LL | |     }
++   | |_____^
++   |
++   = note: `-D clippy::unwrap-in-result` implied by `-D warnings`
++   = help: unwrap and expect should not be used in a function that returns result or option
++note: potential non-recoverable error(s)
++  --> $DIR/unwrap_in_result.rs:24:17
++   |
++LL |         let i = i_str.parse::<i32>().unwrap();
++   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: used unwrap or expect in a function that returns result or option
++  --> $DIR/unwrap_in_result.rs:32:5
++   |
++LL | /     fn example_option_expect(i_str: String) -> Option<bool> {
++LL | |         let i = i_str.parse::<i32>().expect("not a number");
++LL | |         if i % 3 == 0 {
++LL | |             return Some(true);
++LL | |         }
++LL | |         None
++LL | |     }
++   | |_____^
++   |
++   = help: unwrap and expect should not be used in a function that returns result or option
++note: potential non-recoverable error(s)
++  --> $DIR/unwrap_in_result.rs:33:17
++   |
++LL |         let i = i_str.parse::<i32>().expect("not a number");
++   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: aborting due to 2 previous errors
++
index 813cdaecaa91a8864f8f285a8f3c3130c0cb5bc4,0000000000000000000000000000000000000000..8a9b0cd3cf019466d3786f7be3eb08ceda2f0509
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,72 @@@
 +// run-rustfix
 +
 +#![deny(clippy::useless_conversion)]
 +
 +fn test_generic<T: Copy>(val: T) -> T {
 +    let _ = val;
 +    val
 +}
 +
 +fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
 +    // ok
 +    let _: i32 = val.into();
 +    let _: U = val.into();
 +    let _ = U::from(val);
 +}
 +
 +fn test_questionmark() -> Result<(), ()> {
 +    {
 +        let _: i32 = 0i32;
 +        Ok(Ok(()))
 +    }??;
 +    Ok(())
 +}
 +
 +fn test_issue_3913() -> Result<(), std::io::Error> {
 +    use std::fs;
 +    use std::path::Path;
 +
 +    let path = Path::new(".");
 +    for _ in fs::read_dir(path)? {}
 +
 +    Ok(())
 +}
 +
 +fn test_issue_5833() -> Result<(), ()> {
 +    let text = "foo\r\nbar\n\nbaz\n";
 +    let lines = text.lines();
 +    if Some("ok") == lines.into_iter().next() {}
 +
 +    Ok(())
 +}
 +
 +fn main() {
 +    test_generic(10i32);
 +    test_generic2::<i32, i32>(10i32);
 +    test_questionmark().unwrap();
 +    test_issue_3913().unwrap();
 +    test_issue_5833().unwrap();
 +
 +    let _: String = "foo".into();
 +    let _: String = From::from("foo");
 +    let _ = String::from("foo");
 +    #[allow(clippy::useless_conversion)]
 +    {
 +        let _: String = "foo".into();
 +        let _ = String::from("foo");
 +        let _ = "".lines().into_iter();
 +    }
 +
 +    let _: String = "foo".to_string();
 +    let _: String = "foo".to_string();
 +    let _ = "foo".to_string();
 +    let _ = format!("A: {:04}", 123);
 +    let _ = "".lines();
 +    let _ = vec![1, 2, 3].into_iter();
 +    let _: String = format!("Hello {}", "world");
++
++    // keep parenthesis around `a + b` for suggestion (see #4750)
++    let a: i32 = 1;
++    let b: i32 = 1;
++    let _ = (a + b) * 3;
 +}
index 540fea23b36b98e0061e4a7566b0666e04254516,0000000000000000000000000000000000000000..4faa1572973bc0ff5df24d3c2fe392e49d219c0d
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,72 @@@
 +// run-rustfix
 +
 +#![deny(clippy::useless_conversion)]
 +
 +fn test_generic<T: Copy>(val: T) -> T {
 +    let _ = T::from(val);
 +    val.into()
 +}
 +
 +fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
 +    // ok
 +    let _: i32 = val.into();
 +    let _: U = val.into();
 +    let _ = U::from(val);
 +}
 +
 +fn test_questionmark() -> Result<(), ()> {
 +    {
 +        let _: i32 = 0i32.into();
 +        Ok(Ok(()))
 +    }??;
 +    Ok(())
 +}
 +
 +fn test_issue_3913() -> Result<(), std::io::Error> {
 +    use std::fs;
 +    use std::path::Path;
 +
 +    let path = Path::new(".");
 +    for _ in fs::read_dir(path)? {}
 +
 +    Ok(())
 +}
 +
 +fn test_issue_5833() -> Result<(), ()> {
 +    let text = "foo\r\nbar\n\nbaz\n";
 +    let lines = text.lines();
 +    if Some("ok") == lines.into_iter().next() {}
 +
 +    Ok(())
 +}
 +
 +fn main() {
 +    test_generic(10i32);
 +    test_generic2::<i32, i32>(10i32);
 +    test_questionmark().unwrap();
 +    test_issue_3913().unwrap();
 +    test_issue_5833().unwrap();
 +
 +    let _: String = "foo".into();
 +    let _: String = From::from("foo");
 +    let _ = String::from("foo");
 +    #[allow(clippy::useless_conversion)]
 +    {
 +        let _: String = "foo".into();
 +        let _ = String::from("foo");
 +        let _ = "".lines().into_iter();
 +    }
 +
 +    let _: String = "foo".to_string().into();
 +    let _: String = From::from("foo".to_string());
 +    let _ = String::from("foo".to_string());
 +    let _ = String::from(format!("A: {:04}", 123));
 +    let _ = "".lines().into_iter();
 +    let _ = vec![1, 2, 3].into_iter().into_iter();
 +    let _: String = format!("Hello {}", "world").into();
++
++    // keep parenthesis around `a + b` for suggestion (see #4750)
++    let a: i32 = 1;
++    let b: i32 = 1;
++    let _ = i32::from(a + b) * 3;
 +}
index b958b0354520326577fdfcf17d56e932a6b813df,0000000000000000000000000000000000000000..f1e880d2696c40c430e23e11f2a60aec52e5dc7f
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,74 @@@
- error: aborting due to 10 previous errors
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:6:13
 +   |
 +LL |     let _ = T::from(val);
 +   |             ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
 +   |
 +note: the lint level is defined here
 +  --> $DIR/useless_conversion.rs:3:9
 +   |
 +LL | #![deny(clippy::useless_conversion)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:7:5
 +   |
 +LL |     val.into()
 +   |     ^^^^^^^^^^ help: consider removing `.into()`: `val`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:19:22
 +   |
 +LL |         let _: i32 = 0i32.into();
 +   |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:60:21
 +   |
 +LL |     let _: String = "foo".to_string().into();
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:61:21
 +   |
 +LL |     let _: String = From::from("foo".to_string());
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:62:13
 +   |
 +LL |     let _ = String::from("foo".to_string());
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:63:13
 +   |
 +LL |     let _ = String::from(format!("A: {:04}", 123));
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:64:13
 +   |
 +LL |     let _ = "".lines().into_iter();
 +   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:65:13
 +   |
 +LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 +
 +error: useless conversion to the same type
 +  --> $DIR/useless_conversion.rs:66:21
 +   |
 +LL |     let _: String = format!("Hello {}", "world").into();
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 +
++error: useless conversion to the same type
++  --> $DIR/useless_conversion.rs:71:13
++   |
++LL |     let _ = i32::from(a + b) * 3;
++   |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
++
++error: aborting due to 11 previous errors
 +
index e73a791891f890664cf3eddc2f60b63040c4e995,0000000000000000000000000000000000000000..856771596202efb47f1c755759ccf60040133d00
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,62 @@@
 +// run-rustfix
 +
 +#![warn(clippy::useless_vec)]
 +
 +#[derive(Debug)]
 +struct NonCopy;
 +
 +fn on_slice(_: &[u8]) {}
 +#[allow(clippy::ptr_arg)]
 +fn on_vec(_: &Vec<u8>) {}
 +
 +struct Line {
 +    length: usize,
 +}
 +
 +impl Line {
 +    fn length(&self) -> usize {
 +        self.length
 +    }
 +}
 +
 +fn main() {
 +    on_slice(&[]);
 +    on_slice(&[]);
 +
 +    on_slice(&[1, 2]);
 +    on_slice(&[1, 2]);
 +
 +    on_slice(&[1, 2]);
 +    on_slice(&[1, 2]);
 +    #[rustfmt::skip]
 +    on_slice(&[1, 2]);
 +    on_slice(&[1, 2]);
 +
 +    on_slice(&[1; 2]);
 +    on_slice(&[1; 2]);
 +
 +    on_vec(&vec![]);
 +    on_vec(&vec![1, 2]);
 +    on_vec(&vec![1; 2]);
 +
 +    // Now with non-constant expressions
 +    let line = Line { length: 2 };
 +
 +    on_slice(&vec![2; line.length]);
 +    on_slice(&vec![2; line.length()]);
 +
 +    for a in &[1, 2, 3] {
 +        println!("{:?}", a);
 +    }
 +
 +    for a in vec![NonCopy, NonCopy] {
 +        println!("{:?}", a);
 +    }
++
++    on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
++
++    // Ok
++    for a in vec![1; 201] {
++        println!("{:?}", a);
++    }
 +}
index 3eb960f53d7af7dc33dc7baa14a51b36c7f65e05,0000000000000000000000000000000000000000..03b8ee816658ccefbebb278a89e278cc36945691
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,62 @@@
 +// run-rustfix
 +
 +#![warn(clippy::useless_vec)]
 +
 +#[derive(Debug)]
 +struct NonCopy;
 +
 +fn on_slice(_: &[u8]) {}
 +#[allow(clippy::ptr_arg)]
 +fn on_vec(_: &Vec<u8>) {}
 +
 +struct Line {
 +    length: usize,
 +}
 +
 +impl Line {
 +    fn length(&self) -> usize {
 +        self.length
 +    }
 +}
 +
 +fn main() {
 +    on_slice(&vec![]);
 +    on_slice(&[]);
 +
 +    on_slice(&vec![1, 2]);
 +    on_slice(&[1, 2]);
 +
 +    on_slice(&vec![1, 2]);
 +    on_slice(&[1, 2]);
 +    #[rustfmt::skip]
 +    on_slice(&vec!(1, 2));
 +    on_slice(&[1, 2]);
 +
 +    on_slice(&vec![1; 2]);
 +    on_slice(&[1; 2]);
 +
 +    on_vec(&vec![]);
 +    on_vec(&vec![1, 2]);
 +    on_vec(&vec![1; 2]);
 +
 +    // Now with non-constant expressions
 +    let line = Line { length: 2 };
 +
 +    on_slice(&vec![2; line.length]);
 +    on_slice(&vec![2; line.length()]);
 +
 +    for a in vec![1, 2, 3] {
 +        println!("{:?}", a);
 +    }
 +
 +    for a in vec![NonCopy, NonCopy] {
 +        println!("{:?}", a);
 +    }
++
++    on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack`
++
++    // Ok
++    for a in vec![1; 201] {
++        println!("{:?}", a);
++    }
 +}
index 67423e6ec1d19bca17b3acd4b55227ab6cfae2b8,0000000000000000000000000000000000000000..287f8935327c561f0dd7b8543597fbfe5095b9ae
mode 100644,000000..100644
--- /dev/null
@@@ -1,230 -1,0 +1,232 @@@
 +// run-rustfix
 +// aux-build:wildcard_imports_helper.rs
 +
 +#![warn(clippy::wildcard_imports)]
 +//#![allow(clippy::redundant_pub_crate)]
 +#![allow(unused)]
 +#![warn(unused_imports)]
 +
 +extern crate wildcard_imports_helper;
 +
 +use crate::fn_mod::foo;
 +use crate::mod_mod::inner_mod;
 +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
 +#[macro_use]
 +use crate::struct_mod::{A, inner_struct_mod};
 +
 +#[allow(unused_imports)]
 +use wildcard_imports_helper::inner::inner_for_self_import;
 +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 +use wildcard_imports_helper::{ExternA, extern_foo};
 +
 +use std::io::prelude::*;
++use wildcard_imports_helper::prelude::v1::*;
 +
 +struct ReadFoo;
 +
 +impl Read for ReadFoo {
 +    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
 +        Ok(0)
 +    }
 +}
 +
 +mod fn_mod {
 +    pub fn foo() {}
 +}
 +
 +mod mod_mod {
 +    pub mod inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod multi_fn_mod {
 +    pub fn multi_foo() {}
 +    pub fn multi_bar() {}
 +    pub fn multi_baz() {}
 +    pub mod multi_inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod struct_mod {
 +    pub struct A;
 +    pub struct B;
 +    pub mod inner_struct_mod {
 +        pub struct C;
 +    }
 +
 +    #[macro_export]
 +    macro_rules! double_struct_import_test {
 +        () => {
 +            let _ = A;
 +        };
 +    }
 +}
 +
 +fn main() {
 +    foo();
 +    multi_foo();
 +    multi_bar();
 +    multi_inner_mod::foo();
 +    inner_mod::foo();
 +    extern_foo();
 +    inner_extern_bar();
 +
 +    let _ = A;
 +    let _ = inner_struct_mod::C;
 +    let _ = ExternA;
++    let _ = PreludeModAnywhere;
 +
 +    double_struct_import_test!();
 +    double_struct_import_test!();
 +}
 +
 +mod in_fn_test {
 +    pub use self::inner_exported::*;
 +    #[allow(unused_imports)]
 +    pub(crate) use self::inner_exported2::*;
 +
 +    fn test_intern() {
 +        use crate::fn_mod::foo;
 +
 +        foo();
 +    }
 +
 +    fn test_extern() {
 +        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
 +        use wildcard_imports_helper::{ExternA, extern_foo};
 +
 +        inner_for_self_import::inner_extern_foo();
 +        inner_extern_foo();
 +
 +        extern_foo();
 +
 +        let _ = ExternA;
 +    }
 +
 +    fn test_inner_nested() {
 +        use self::{inner::inner_foo, inner2::inner_bar};
 +
 +        inner_foo();
 +        inner_bar();
 +    }
 +
 +    fn test_extern_reexported() {
 +        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
 +
 +        extern_exported();
 +        let _ = ExternExportedStruct;
 +        let _ = ExternExportedEnum::A;
 +    }
 +
 +    mod inner_exported {
 +        pub fn exported() {}
 +        pub struct ExportedStruct;
 +        pub enum ExportedEnum {
 +            A,
 +        }
 +    }
 +
 +    mod inner_exported2 {
 +        pub(crate) fn exported2() {}
 +    }
 +
 +    mod inner {
 +        pub fn inner_foo() {}
 +    }
 +
 +    mod inner2 {
 +        pub fn inner_bar() {}
 +    }
 +}
 +
 +fn test_reexported() {
 +    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
 +
 +    exported();
 +    let _ = ExportedStruct;
 +    let _ = ExportedEnum::A;
 +}
 +
 +#[rustfmt::skip]
 +fn test_weird_formatting() {
 +    use crate:: in_fn_test::exported;
 +    use crate:: fn_mod::foo;
 +
 +    exported();
 +    foo();
 +}
 +
 +mod super_imports {
 +    fn foofoo() {}
 +
 +    mod should_be_replaced {
 +        use super::foofoo;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_inside_function {
 +        fn with_super_inside_function() {
 +            use super::*;
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_further_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod should_be_replaced_futher_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::insidefoo;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod use_explicit_should_be_replaced {
 +        use super_imports::foofoo;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod use_double_super_should_be_replaced {
 +        mod inner {
 +            use super::super::foofoo;
 +
 +            fn with_double_super() {
 +                let _ = foofoo();
 +            }
 +        }
 +    }
 +
 +    mod use_super_explicit_should_be_replaced {
 +        use super::super::super_imports::foofoo;
 +
 +        fn with_super_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +}
index 3ad1a29aebad1f985a19e272ac55f071263f511c,0000000000000000000000000000000000000000..1f261159f4a94e2f32b2c44237e66e2ea62510d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,231 -1,0 +1,233 @@@
 +// run-rustfix
 +// aux-build:wildcard_imports_helper.rs
 +
 +#![warn(clippy::wildcard_imports)]
 +//#![allow(clippy::redundant_pub_crate)]
 +#![allow(unused)]
 +#![warn(unused_imports)]
 +
 +extern crate wildcard_imports_helper;
 +
 +use crate::fn_mod::*;
 +use crate::mod_mod::*;
 +use crate::multi_fn_mod::*;
 +#[macro_use]
 +use crate::struct_mod::*;
 +
 +#[allow(unused_imports)]
 +use wildcard_imports_helper::inner::inner_for_self_import;
 +use wildcard_imports_helper::inner::inner_for_self_import::*;
 +use wildcard_imports_helper::*;
 +
 +use std::io::prelude::*;
++use wildcard_imports_helper::prelude::v1::*;
 +
 +struct ReadFoo;
 +
 +impl Read for ReadFoo {
 +    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
 +        Ok(0)
 +    }
 +}
 +
 +mod fn_mod {
 +    pub fn foo() {}
 +}
 +
 +mod mod_mod {
 +    pub mod inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod multi_fn_mod {
 +    pub fn multi_foo() {}
 +    pub fn multi_bar() {}
 +    pub fn multi_baz() {}
 +    pub mod multi_inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod struct_mod {
 +    pub struct A;
 +    pub struct B;
 +    pub mod inner_struct_mod {
 +        pub struct C;
 +    }
 +
 +    #[macro_export]
 +    macro_rules! double_struct_import_test {
 +        () => {
 +            let _ = A;
 +        };
 +    }
 +}
 +
 +fn main() {
 +    foo();
 +    multi_foo();
 +    multi_bar();
 +    multi_inner_mod::foo();
 +    inner_mod::foo();
 +    extern_foo();
 +    inner_extern_bar();
 +
 +    let _ = A;
 +    let _ = inner_struct_mod::C;
 +    let _ = ExternA;
++    let _ = PreludeModAnywhere;
 +
 +    double_struct_import_test!();
 +    double_struct_import_test!();
 +}
 +
 +mod in_fn_test {
 +    pub use self::inner_exported::*;
 +    #[allow(unused_imports)]
 +    pub(crate) use self::inner_exported2::*;
 +
 +    fn test_intern() {
 +        use crate::fn_mod::*;
 +
 +        foo();
 +    }
 +
 +    fn test_extern() {
 +        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
 +        use wildcard_imports_helper::*;
 +
 +        inner_for_self_import::inner_extern_foo();
 +        inner_extern_foo();
 +
 +        extern_foo();
 +
 +        let _ = ExternA;
 +    }
 +
 +    fn test_inner_nested() {
 +        use self::{inner::*, inner2::*};
 +
 +        inner_foo();
 +        inner_bar();
 +    }
 +
 +    fn test_extern_reexported() {
 +        use wildcard_imports_helper::*;
 +
 +        extern_exported();
 +        let _ = ExternExportedStruct;
 +        let _ = ExternExportedEnum::A;
 +    }
 +
 +    mod inner_exported {
 +        pub fn exported() {}
 +        pub struct ExportedStruct;
 +        pub enum ExportedEnum {
 +            A,
 +        }
 +    }
 +
 +    mod inner_exported2 {
 +        pub(crate) fn exported2() {}
 +    }
 +
 +    mod inner {
 +        pub fn inner_foo() {}
 +    }
 +
 +    mod inner2 {
 +        pub fn inner_bar() {}
 +    }
 +}
 +
 +fn test_reexported() {
 +    use crate::in_fn_test::*;
 +
 +    exported();
 +    let _ = ExportedStruct;
 +    let _ = ExportedEnum::A;
 +}
 +
 +#[rustfmt::skip]
 +fn test_weird_formatting() {
 +    use crate:: in_fn_test::  * ;
 +    use crate:: fn_mod::
 +        *;
 +
 +    exported();
 +    foo();
 +}
 +
 +mod super_imports {
 +    fn foofoo() {}
 +
 +    mod should_be_replaced {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_inside_function {
 +        fn with_super_inside_function() {
 +            use super::*;
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_further_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod should_be_replaced_futher_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod use_explicit_should_be_replaced {
 +        use super_imports::*;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod use_double_super_should_be_replaced {
 +        mod inner {
 +            use super::super::*;
 +
 +            fn with_double_super() {
 +                let _ = foofoo();
 +            }
 +        }
 +    }
 +
 +    mod use_super_explicit_should_be_replaced {
 +        use super::super::super_imports::*;
 +
 +        fn with_super_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +}
index fab43b738eb434d1ab6b453dffbc8967bfeeb222,0000000000000000000000000000000000000000..351988f31ead5b881c5086951cb42fc2e6af9b69
mode 100644,000000..100644
--- /dev/null
@@@ -1,126 -1,0 +1,126 @@@
-   --> $DIR/wildcard_imports.rs:89:13
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:11:5
 +   |
 +LL | use crate::fn_mod::*;
 +   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 +   |
 +   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 +
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:12:5
 +   |
 +LL | use crate::mod_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 +
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:13:5
 +   |
 +LL | use crate::multi_fn_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 +
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:15:5
 +   |
 +LL | use crate::struct_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 +
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:19:5
 +   |
 +LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 +
 +error: usage of wildcard import
 +  --> $DIR/wildcard_imports.rs:20:5
 +   |
 +LL | use wildcard_imports_helper::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:95:75
++  --> $DIR/wildcard_imports.rs:91:13
 +   |
 +LL |         use crate::fn_mod::*;
 +   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:96:13
++  --> $DIR/wildcard_imports.rs:97:75
 +   |
 +LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
 +   |                                                                           ^ help: try: `inner_extern_foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:107:20
++  --> $DIR/wildcard_imports.rs:98:13
 +   |
 +LL |         use wildcard_imports_helper::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:107:30
++  --> $DIR/wildcard_imports.rs:109:20
 +   |
 +LL |         use self::{inner::*, inner2::*};
 +   |                    ^^^^^^^^ help: try: `inner::inner_foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:114:13
++  --> $DIR/wildcard_imports.rs:109:30
 +   |
 +LL |         use self::{inner::*, inner2::*};
 +   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:143:9
++  --> $DIR/wildcard_imports.rs:116:13
 +   |
 +LL |         use wildcard_imports_helper::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:152:9
++  --> $DIR/wildcard_imports.rs:145:9
 +   |
 +LL |     use crate::in_fn_test::*;
 +   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:153:9
++  --> $DIR/wildcard_imports.rs:154:9
 +   |
 +LL |     use crate:: in_fn_test::  * ;
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:164:13
++  --> $DIR/wildcard_imports.rs:155:9
 +   |
 +LL |       use crate:: fn_mod::
 +   |  _________^
 +LL | |         *;
 +   | |_________^ help: try: `crate:: fn_mod::foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:199:17
++  --> $DIR/wildcard_imports.rs:166:13
 +   |
 +LL |         use super::*;
 +   |             ^^^^^^^^ help: try: `super::foofoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:207:13
++  --> $DIR/wildcard_imports.rs:201:17
 +   |
 +LL |             use super::*;
 +   |                 ^^^^^^^^ help: try: `super::insidefoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:216:17
++  --> $DIR/wildcard_imports.rs:209:13
 +   |
 +LL |         use super_imports::*;
 +   |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:225:13
++  --> $DIR/wildcard_imports.rs:218:17
 +   |
 +LL |             use super::super::*;
 +   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 +
 +error: usage of wildcard import
++  --> $DIR/wildcard_imports.rs:227:13
 +   |
 +LL |         use super::super::super_imports::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 +
 +error: aborting due to 20 previous errors
 +
index 99652ca4470c2a47530812a3b78f0e2381f68ec3,0000000000000000000000000000000000000000..f44305d7e483855614d8ce52a5ea3cb15bea0492
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,90 @@@
++// edition:2018
 +#![warn(clippy::wrong_self_convention)]
 +#![warn(clippy::wrong_pub_self_convention)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +#[derive(Clone, Copy)]
 +struct Foo;
 +
 +impl Foo {
 +    fn as_i32(self) {}
 +    fn as_u32(&self) {}
 +    fn into_i32(self) {}
 +    fn is_i32(self) {}
 +    fn is_u32(&self) {}
 +    fn to_i32(self) {}
 +    fn from_i32(self) {}
 +
 +    pub fn as_i64(self) {}
 +    pub fn into_i64(self) {}
 +    pub fn is_i64(self) {}
 +    pub fn to_i64(self) {}
 +    pub fn from_i64(self) {}
 +    // check whether the lint can be allowed at the function level
 +    #[allow(clippy::wrong_self_convention)]
 +    pub fn from_cake(self) {}
 +
 +    fn as_x<F: AsRef<Self>>(_: F) {}
 +    fn as_y<F: AsRef<Foo>>(_: F) {}
 +}
 +
 +struct Bar;
 +
 +impl Bar {
 +    fn as_i32(self) {}
 +    fn as_u32(&self) {}
 +    fn into_i32(&self) {}
 +    fn into_u32(self) {}
 +    fn is_i32(self) {}
 +    fn is_u32(&self) {}
 +    fn to_i32(self) {}
 +    fn to_u32(&self) {}
 +    fn from_i32(self) {}
 +
 +    pub fn as_i64(self) {}
 +    pub fn into_i64(&self) {}
 +    pub fn is_i64(self) {}
 +    pub fn to_i64(self) {}
 +    pub fn from_i64(self) {}
 +
 +    // test for false positives
 +    fn as_(self) {}
 +    fn into_(&self) {}
 +    fn is_(self) {}
 +    fn to_(self) {}
 +    fn from_(self) {}
 +    fn to_mut(&mut self) {}
 +}
 +
 +// Allow Box<Self>, Rc<Self>, Arc<Self> for methods that take conventionally take Self by value
 +#[allow(clippy::boxed_local)]
 +mod issue4293 {
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    struct T;
 +
 +    impl T {
 +        fn into_s1(self: Box<Self>) {}
 +        fn into_s2(self: Rc<Self>) {}
 +        fn into_s3(self: Arc<Self>) {}
 +
 +        fn into_t1(self: Box<T>) {}
 +        fn into_t2(self: Rc<T>) {}
 +        fn into_t3(self: Arc<T>) {}
 +    }
 +}
++
++// False positive for async (see #4037)
++mod issue4037 {
++    pub struct Foo;
++    pub struct Bar;
++
++    impl Foo {
++        pub async fn into_bar(self) -> Bar {
++            Bar
++        }
++    }
++}
index 0d0eb19cd072333012d91cc384e5b6a2031e199a,0000000000000000000000000000000000000000..ef3ad73ebc7c18cada8aaf7825cb843318343af3
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,76 @@@
-   --> $DIR/wrong_self_convention.rs:17:17
 +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:23:21
++  --> $DIR/wrong_self_convention.rs:18:17
 +   |
 +LL |     fn from_i32(self) {}
 +   |                 ^^^^
 +   |
 +   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 +
 +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:35:15
++  --> $DIR/wrong_self_convention.rs:24:21
 +   |
 +LL |     pub fn from_i64(self) {}
 +   |                     ^^^^
 +
 +error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:37:17
++  --> $DIR/wrong_self_convention.rs:36:15
 +   |
 +LL |     fn as_i32(self) {}
 +   |               ^^^^
 +
 +error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:39:15
++  --> $DIR/wrong_self_convention.rs:38:17
 +   |
 +LL |     fn into_i32(&self) {}
 +   |                 ^^^^^
 +
 +error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:41:15
++  --> $DIR/wrong_self_convention.rs:40:15
 +   |
 +LL |     fn is_i32(self) {}
 +   |               ^^^^
 +
 +error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:43:17
++  --> $DIR/wrong_self_convention.rs:42:15
 +   |
 +LL |     fn to_i32(self) {}
 +   |               ^^^^
 +
 +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:45:19
++  --> $DIR/wrong_self_convention.rs:44:17
 +   |
 +LL |     fn from_i32(self) {}
 +   |                 ^^^^
 +
 +error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:46:21
++  --> $DIR/wrong_self_convention.rs:46:19
 +   |
 +LL |     pub fn as_i64(self) {}
 +   |                   ^^^^
 +
 +error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:47:19
++  --> $DIR/wrong_self_convention.rs:47:21
 +   |
 +LL |     pub fn into_i64(&self) {}
 +   |                     ^^^^^
 +
 +error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:48:19
++  --> $DIR/wrong_self_convention.rs:48:19
 +   |
 +LL |     pub fn is_i64(self) {}
 +   |                   ^^^^
 +
 +error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-   --> $DIR/wrong_self_convention.rs:49:21
++  --> $DIR/wrong_self_convention.rs:49:19
 +   |
 +LL |     pub fn to_i64(self) {}
 +   |                   ^^^^
 +
 +error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
++  --> $DIR/wrong_self_convention.rs:50:21
 +   |
 +LL |     pub fn from_i64(self) {}
 +   |                     ^^^^
 +
 +error: aborting due to 12 previous errors
 +