]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit 'b7f3f7f6082679da2da9a0b3faf1b5adef3afd3b' into clippyup
authorflip1995 <philipp.krones@embecosm.com>
Thu, 7 Oct 2021 09:21:30 +0000 (11:21 +0200)
committerflip1995 <philipp.krones@embecosm.com>
Thu, 7 Oct 2021 09:21:30 +0000 (11:21 +0200)
147 files changed:
1  2 
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_dev/src/lib.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
src/tools/clippy/clippy_lints/src/derivable_impls.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/equatable_if_let.rs
src/tools/clippy/clippy_lints/src/erasing_op.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/if_then_panic.rs
src/tools/clippy/clippy_lints/src/implicit_hasher.rs
src/tools/clippy/clippy_lints/src/integer_division.rs
src/tools/clippy/clippy_lints/src/large_enum_variant.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.deprecated.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_cargo.rs
src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
src/tools/clippy/clippy_lints/src/lib.register_internal.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.register_perf.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
src/tools/clippy/clippy_lints/src/loops/never_loop.rs
src/tools/clippy/clippy_lints/src/manual_async_fn.rs
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
src/tools/clippy/clippy_lints/src/needless_bool.rs
src/tools/clippy/clippy_lints/src/neg_multiply.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/repeat_once.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/transmuting_null.rs
src/tools/clippy/clippy_lints/src/types/option_option.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/zero_div_zero.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/numeric_literal.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/clippy_utils/src/usage.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml
src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs
src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/approx_const.rs
src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
src/tools/clippy/tests/ui/collapsible_else_if.fixed
src/tools/clippy/tests/ui/collapsible_else_if.rs
src/tools/clippy/tests/ui/collapsible_if.fixed
src/tools/clippy/tests/ui/collapsible_if.rs
src/tools/clippy/tests/ui/collapsible_match.rs
src/tools/clippy/tests/ui/collapsible_match.stderr
src/tools/clippy/tests/ui/crashes/ice-3462.rs
src/tools/clippy/tests/ui/def_id_nocore.rs
src/tools/clippy/tests/ui/def_id_nocore.stderr
src/tools/clippy/tests/ui/derivable_impls.rs
src/tools/clippy/tests/ui/derivable_impls.stderr
src/tools/clippy/tests/ui/doc/doc.rs
src/tools/clippy/tests/ui/doc_unsafe.rs
src/tools/clippy/tests/ui/doc_unsafe.stderr
src/tools/clippy/tests/ui/equatable_if_let.fixed
src/tools/clippy/tests/ui/equatable_if_let.rs
src/tools/clippy/tests/ui/equatable_if_let.stderr
src/tools/clippy/tests/ui/excessive_precision.fixed
src/tools/clippy/tests/ui/excessive_precision.rs
src/tools/clippy/tests/ui/excessive_precision.stderr
src/tools/clippy/tests/ui/for_loop_fixable.fixed
src/tools/clippy/tests/ui/for_loop_fixable.rs
src/tools/clippy/tests/ui/for_loop_fixable.stderr
src/tools/clippy/tests/ui/for_loop_unfixable.rs
src/tools/clippy/tests/ui/for_loop_unfixable.stderr
src/tools/clippy/tests/ui/if_same_then_else2.rs
src/tools/clippy/tests/ui/if_same_then_else2.stderr
src/tools/clippy/tests/ui/if_then_panic.fixed
src/tools/clippy/tests/ui/if_then_panic.rs
src/tools/clippy/tests/ui/if_then_panic.stderr
src/tools/clippy/tests/ui/implicit_hasher.rs
src/tools/clippy/tests/ui/implicit_hasher.stderr
src/tools/clippy/tests/ui/integer_arithmetic.rs
src/tools/clippy/tests/ui/integer_arithmetic.stderr
src/tools/clippy/tests/ui/large_enum_variant.rs
src/tools/clippy/tests/ui/large_enum_variant.stderr
src/tools/clippy/tests/ui/map_clone.fixed
src/tools/clippy/tests/ui/map_clone.rs
src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
src/tools/clippy/tests/ui/match_overlapping_arm.rs
src/tools/clippy/tests/ui/match_ref_pats.rs
src/tools/clippy/tests/ui/match_ref_pats.stderr
src/tools/clippy/tests/ui/modulo_arithmetic_float.rs
src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs
src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs
src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
src/tools/clippy/tests/ui/needless_bool/fixable.fixed
src/tools/clippy/tests/ui/needless_bool/fixable.rs
src/tools/clippy/tests/ui/needless_bool/fixable.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
src/tools/clippy/tests/ui/option_if_let_else.fixed
src/tools/clippy/tests/ui/option_if_let_else.rs
src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs
src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
src/tools/clippy/tests/ui/shadow.rs
src/tools/clippy/tests/ui/shadow.stderr
src/tools/clippy/tests/ui/suspicious_map.stderr
src/tools/clippy/tests/ui/while_let_on_iterator.fixed
src/tools/clippy/tests/ui/while_let_on_iterator.rs
src/tools/clippy/tests/ui/while_let_on_iterator.stderr
src/tools/clippy/util/etc/pre-commit.sh

index 58ea0f9ab9d286f6229db205a99a7983c7d43ba0,0000000000000000000000000000000000000000..7fdb300c9774194d48605468f63eb8018fe12dbe
mode 100644,000000..100644
--- /dev/null
@@@ -1,3106 -1,0 +1,3108 @@@
 +# 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
 +
 +[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
 +
 +## Rust 1.56
 +
 +Current beta, release 2021-10-21
 +
 +[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
 +
 +### New Lints
 +
 +* [`unwrap_or_else_default`]
 +  [#7516](https://github.com/rust-lang/rust-clippy/pull/7516)
 +
 +### Enhancements
 +
 +* [`needless_continue`]: Now also lints in `loop { continue; }` case
 +  [#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
 +* [`disallowed_type`]: Now also primitive types can be disallowed
 +  [#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
 +* [`manual_swap`]: Now also lints on xor swaps
 +  [#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
 +* [`map_flatten`]: Now also lints on the `Result` type
 +  [#7522](https://github.com/rust-lang/rust-clippy/pull/7522)
 +* [`no_effect`]: Now also lints on inclusive ranges
 +  [#7556](https://github.com/rust-lang/rust-clippy/pull/7556)
 +
 +### False Positive Fixes
 +
 +* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros
 +  [#7478](https://github.com/rust-lang/rust-clippy/pull/7478)
 +* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics
 +  [#7534](https://github.com/rust-lang/rust-clippy/pull/7534)
 +* [`similar_names`]: No longer complains about `iter` and `item` being too
 +  similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`similar_names`]: No longer suggests to insert or add an underscore as a fix
 +  [#7221](https://github.com/rust-lang/rust-clippy/pull/7221)
 +* [`new_without_default`]: No longer shows the full qualified type path when
 +  suggesting adding a `Default` implementation
 +  [#7493](https://github.com/rust-lang/rust-clippy/pull/7493)
 +* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references
 +  [#7520](https://github.com/rust-lang/rust-clippy/pull/7520)
 +* [`extend_with_drain`]: Improve code suggestion for mutable and immutable
 +  references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533)
 +* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type
 +  [#7535](https://github.com/rust-lang/rust-clippy/pull/7535)
 +* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when
 +  applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541)
 +
 +### Documentation Improvements
 +
 +* Clippy now uses a lint to generate its lint documentation. [Lints all the way
 +  down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
 +  [#7502](https://github.com/rust-lang/rust-clippy/pull/7502)
 +* Reworked Clippy's website:
 +  [#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
 +  [#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
 +  * Added applicability information about lints
 +  * Added a link to jump into the implementation
 +  * Improved loading times
 +  * Adapted some styling
 +* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag
 +  [#7492](https://github.com/rust-lang/rust-clippy/pull/7492)
 +* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
 +  example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
 +
 +### New Lints
 +
 +* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
 +
 +## Rust 1.55
 +
 +Current stable, released 2021-09-09
 +
 +[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
 +
 +### Important Changes
 +
 +* Stabilized `cargo clippy --fix` :tada:
 +  [#7405](https://github.com/rust-lang/rust-clippy/pull/7405)
 +
 +### New Lints
 +
 +* [`rc_mutex`]
 +  [#7316](https://github.com/rust-lang/rust-clippy/pull/7316)
 +* [`nonstandard_macro_braces`]
 +  [#7299](https://github.com/rust-lang/rust-clippy/pull/7299)
 +* [`strlen_on_c_strings`]
 +  [#7243](https://github.com/rust-lang/rust-clippy/pull/7243)
 +* [`self_named_constructors`]
 +  [#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
 +* [`disallowed_script_idents`]
 +  [#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
 +* [`disallowed_type`]
 +  [#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
 +* [`missing_enforced_import_renames`]
 +  [#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
 +* [`extend_with_drain`]
 +  [#7270](https://github.com/rust-lang/rust-clippy/pull/7270)
 +
 +### Moves and Deprecations
 +
 +* Moved [`from_iter_instead_of_collect`] to `pedantic`
 +  [#7375](https://github.com/rust-lang/rust-clippy/pull/7375)
 +* Added `suspicious` as a new lint group for *code that is most likely wrong or useless*
 +  [#7350](https://github.com/rust-lang/rust-clippy/pull/7350)
 +  * Moved [`blanket_clippy_restriction_lints`] to `suspicious`
 +  * Moved [`empty_loop`] to `suspicious`
 +  * Moved [`eval_order_dependence`] to `suspicious`
 +  * Moved [`float_equality_without_abs`] to `suspicious`
 +  * Moved [`for_loops_over_fallibles`] to `suspicious`
 +  * Moved [`misrefactored_assign_op`] to `suspicious`
 +  * Moved [`mut_range_bound`] to `suspicious`
 +  * Moved [`mutable_key_type`] to `suspicious`
 +  * Moved [`suspicious_arithmetic_impl`] to `suspicious`
 +  * Moved [`suspicious_assignment_formatting`] to `suspicious`
 +  * Moved [`suspicious_else_formatting`] to `suspicious`
 +  * Moved [`suspicious_map`] to `suspicious`
 +  * Moved [`suspicious_op_assign_impl`] to `suspicious`
 +  * Moved [`suspicious_unary_op_formatting`] to `suspicious`
 +
 +### Enhancements
 +
 +* [`while_let_on_iterator`]: Now suggests `&mut iter` inside closures
 +  [#7262](https://github.com/rust-lang/rust-clippy/pull/7262)
 +* [`doc_markdown`]:
 +  * Now detects unbalanced ticks
 +    [#7357](https://github.com/rust-lang/rust-clippy/pull/7357)
 +  * Add `FreeBSD` to the default configuration as an allowed identifier
 +    [#7334](https://github.com/rust-lang/rust-clippy/pull/7334)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: Now allows wildcards for enums with unstable
 +  or hidden variants
 +  [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 +* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
 +  [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
 +* [`blacklisted_name`]: Now allows blacklisted names in test code
 +  [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 +* [`redundant_closure`]: Suggests `&mut` for `FnMut`
 +  [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
 +* [`disallowed_method`], [`disallowed_type`]: The configuration values `disallowed-method` and `disallowed-type`
 +  no longer require fully qualified paths
 +  [#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
 +* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
 +  [#7396](https://github.com/rust-lang/rust-clippy/pull/7396)
 +
 +### False Positive Fixes
 +
 +* [`default_numeric_fallback`]: No longer lints on float literals as function arguments
 +  [#7446](https://github.com/rust-lang/rust-clippy/pull/7446)
 +* [`use_self`]: No longer lints on type parameters
 +  [#7288](https://github.com/rust-lang/rust-clippy/pull/7288)
 +* [`unimplemented`]: Now ignores the `assert` and `debug_assert` macros
 +  [#7439](https://github.com/rust-lang/rust-clippy/pull/7439)
 +* [`branches_sharing_code`]: Now always checks for block expressions
 +  [#7462](https://github.com/rust-lang/rust-clippy/pull/7462)
 +* [`field_reassign_with_default`]: No longer triggers in macros
 +  [#7160](https://github.com/rust-lang/rust-clippy/pull/7160)
 +* [`redundant_clone`]: No longer lints on required clones for borrowed data
 +  [#7346](https://github.com/rust-lang/rust-clippy/pull/7346)
 +* [`default_numeric_fallback`]: No longer triggers in external macros
 +  [#7325](https://github.com/rust-lang/rust-clippy/pull/7325)
 +* [`needless_bool`]: No longer lints in macros
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`useless_format`]: No longer triggers when additional text is being appended
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`assertions_on_constants`]: `cfg!(...)` is no longer considered to be a constant
 +  [#7319](https://github.com/rust-lang/rust-clippy/pull/7319)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`needless_collect`]: Now show correct lint messages for shadowed values
 +  [#7289](https://github.com/rust-lang/rust-clippy/pull/7289)
 +* [`wrong_pub_self_convention`]: The deprecated message now suggest the correct configuration value
 +  [#7382](https://github.com/rust-lang/rust-clippy/pull/7382)
 +* [`semicolon_if_nothing_returned`]: Allow missing semicolon in blocks with only one expression
 +  [#7326](https://github.com/rust-lang/rust-clippy/pull/7326)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#7470](https://github.com/rust-lang/rust-clippy/pull/7470)
 +* [`redundant_pattern_matching`]
 +  [#7471](https://github.com/rust-lang/rust-clippy/pull/7471)
 +* [`modulo_one`]
 +  [#7473](https://github.com/rust-lang/rust-clippy/pull/7473)
 +* [`use_self`]
 +  [#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
 +
 +## Rust 1.54
 +
 +Released 2021-07-29
 +
 +[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
 +
 +### New Lints
 +
 +- [`ref_binding_to_reference`]
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`needless_bitwise_bool`]
 +  [#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
 +- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
 +- [`manual_str_repeat`]
 +  [#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
 +- [`suspicious_splitn`]
 +  [#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
 +
 +### Moves and Deprecations
 +
 +- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
 +  the new `avoid-breaking-exported-api` config option (see
 +  [Enhancements](#1-54-enhancements))
 +  [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- Move [`inconsistent_struct_constructor`] to `pedantic`
 +  [#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
 +- Move [`needless_borrow`] to `style` (now warn-by-default)
 +  [#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
 +- Move [`suspicious_operation_groupings`] to `nursery`
 +  [#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
 +- Move [`semicolon_if_nothing_returned`] to `pedantic`
 +  [#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
 +
 +### Enhancements <a name="1-54-enhancements"></a>
 +
 +- [`while_let_on_iterator`]: Now also lints in nested loops
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
 +  [#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
 +- [`needless_collect`]: Now also lints on assignments with type annotations
 +  [#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
 +- [`if_then_some_else_none`]: Now works with the MSRV config
 +  [#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
 +- Add `avoid-breaking-exported-api` config option for the lints
 +  [`enum_variant_names`], [`large_types_passed_by_value`],
 +  [`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
 +  [`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
 +  this configuration option to `false` before a major release (1.0/2.0/...) to
 +  clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- [`needless_collect`]: Now lints on even more data structures
 +  [#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
 +- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
 +  attributes as sufficient documentation
 +  [#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
 +- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
 +  Now work as expected when used with `allow`
 +  [#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
 +
 +### False Positive Fixes
 +
 +- [`implicit_return`]: Now takes all diverging functions in account to avoid
 +  false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
 +  and the struct is used in the loop
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`multiple_inherent_impl`]: No longer lints with generic arguments
 +  [#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
 +- [`comparison_chain`]: No longer lints in a `const` context
 +  [#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
 +- [`while_immutable_condition`]: Fix false positive where mutation in the loop
 +  variable wasn't picked up
 +  [#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
 +- [`default_trait_access`]: No longer lints in macros
 +  [#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
 +- [`needless_question_mark`]: No longer lints when the inner value is implicitly
 +  dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
 +- [`unused_unit`]: No longer lints when multiple macro contexts are involved
 +  [#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
 +- [`eval_order_dependence`]: Fix false positive in async context
 +  [#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
 +- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
 +  type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
 +- [`wrong_self_convention`]: No longer lints in trait implementations of
 +  non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
 +- [`suboptimal_flops`]: No longer lints on `powi(2)`
 +  [#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
 +- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
 +  [#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
 +- [`option_if_let_else`]: No longer lints on `else if let` pattern
 +  [#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
 +- [`use_self`], [`useless_conversion`]: Fix false positives when generic
 +  arguments are involved
 +  [#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
 +- [`manual_unwrap_or`]: Fix false positive with deref coercion
 +  [#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
 +- [`similar_names`]: No longer lints on `wparam`/`lparam`
 +  [#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
 +- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
 +  closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
 +
 +### Suggestion Fixes/Improvements
 +
 +- [`implicit_return`]
 +  [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +    - Fix suggestion for async functions
 +    - Improve suggestion with macros
 +    - Suggest to change `break` to `return` when appropriate
 +- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`match_single_binding`]: Improve suggestion when match scrutinee has side
 +  effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
 +- [`needless_borrow`]: Now suggests to also change usage sites as needed
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
 +  buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
 +- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
 +  when a `<_ as Trait>::_` is involved
 +  [#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
 +- [`not_unsafe_ptr_arg_deref`]: Improved error message
 +  [#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
 +
 +### ICE Fixes
 +
 +- Fix ICE when running Clippy on `libstd`
 +  [#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
 +- [`implicit_return`]
 +  [#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
 +
 +## Rust 1.53
 +
 +Released 2021-06-17
 +
 +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
 +
 +### New Lints
 +
 +* [`option_filter_map`]
 +  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
 +* [`branches_sharing_code`]
 +  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
 +* [`needless_for_each`]
 +  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
 +* [`if_then_some_else_none`]
 +  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
 +* [`non_octal_unix_permissions`]
 +  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
 +* [`unnecessary_self_imports`]
 +  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
 +* [`bool_assert_comparison`]
 +  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
 +* [`cloned_instead_of_copied`]
 +  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
 +* [`flat_map_option`]
 +  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`filter_map`] lint
 +  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
 +* Move [`transmute_ptr_to_ptr`] to `pedantic`
 +  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
 +
 +### Enhancements
 +
 +* [`mem_replace_with_default`]: Also lint on common std constructors
 +  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
 +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
 +  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
 +  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
 +    * Attempt to find a common path prefix in suggestion
 +    * Don't lint on `Option` and `Result`
 +    * Consider `Self` prefix
 +* [`explicit_deref_methods`]: Also lint on chained `deref` calls
 +  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
 +* [`or_fun_call`]: Also lint on `unsafe` blocks
 +  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
 +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
 +  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
 +* [`search_is_some`]: Also check for `is_none`
 +  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
 +* [`string_lit_as_bytes`]: Also lint on `into_bytes`
 +  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
 +* [`len_without_is_empty`]: Also lint if function signatures of `len` and
 +  `is_empty` don't match
 +  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
 +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
 +  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
 +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
 +  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
 +* [`needless_return`]: Also lint in `async` functions
 +  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
 +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
 +  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
 +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
 +  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
 +
 +### False Positive Fixes
 +
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
 +* [`suspicious_map`]: No longer lints when side effects may occur inside the
 +  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
 +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
 +  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
 +* [`wrong_self_convention`]: Now respects `Copy` types
 +  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
 +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
 +  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
 +* [`map_entry`]: Better detect if the entry API can be used
 +  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`or_fun_call`]: No longer lints on some `len` function calls
 +  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
 +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
 +  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
 +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
 +  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
 +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
 +  suggesting to use `derive` instead
 +  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
 +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
 +  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
 +* [`clone_on_copy`]: Only lint when using the `Clone` trait
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`wrong_self_convention`]: No longer lints inside a trait implementation
 +  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
 +* [`redundant_clone`]: No longer lints when the cloned value is modified while
 +  the clone is in use
 +  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
 +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
 +  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
 +* [`cargo_common_metadata`]: Remove author requirement
 +  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
 +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
 +  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
 +* [`panic`]: No longer wrongfully lints on `debug_assert` with message
 +  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
 +* [`wrong_self_convention`]: No longer lints in trait implementations where no
 +  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
 +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
 +  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
 +* [`suspicious_else_formatting`]: Allow Allman style braces
 +  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
 +* [`inconsistent_struct_constructor`]: No longer lints in macros
 +  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
 +* [`single_component_path_imports`]: No longer lints on macro re-exports
 +  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`redundant_pattern_matching`]: Add a note when applying this lint would
 +  change the drop order
 +  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
 +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
 +  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
 +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
 +  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
 +* [`inconsistent_struct_constructor`]: Make lint description and message clearer
 +  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
 +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
 +  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`manual_flatten`]: Suggest to insert `copied` if necessary
 +  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
 +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
 +  when the value is from a macro call
 +  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
 +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
 +  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
 +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`manual_map`]: Fix suggestion at the end of an if chain
 +  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
 +* Fix needless parenthesis output in multiple lint suggestions
 +  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
 +* [`needless_collect`]: Better explanation in the lint message
 +  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
 +* [`useless_vec`]: Now considers mutability
 +  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
 +* [`useless_format`]: Wrap the content in braces if necessary
 +  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
 +* [`single_match`]: Don't suggest an equality check for types which don't
 +  implement `PartialEq`
 +  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
 +* [`from_over_into`]: Mention type in help message
 +  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
 +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
 +  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
 +
 +### ICE Fixes
 +
 +* [`macro_use_imports`]
 +  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
 +* [`missing_panics_doc`]
 +  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
 +* [`tabs_in_doc_comments`]
 +  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
 +* [`missing_const_for_fn`]
 +  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
 +  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
 +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
 +  deprecation warning
 +  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 +
 +## Rust 1.52
 +
 +Released 2021-05-06
 +
 +[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 +
 +### New Lints
 +
 +* [`from_str_radix_10`]
 +  [#6717](https://github.com/rust-lang/rust-clippy/pull/6717)
 +* [`implicit_clone`]
 +  [#6730](https://github.com/rust-lang/rust-clippy/pull/6730)
 +* [`semicolon_if_nothing_returned`]
 +  [#6681](https://github.com/rust-lang/rust-clippy/pull/6681)
 +* [`manual_flatten`]
 +  [#6646](https://github.com/rust-lang/rust-clippy/pull/6646)
 +* [`inconsistent_struct_constructor`]
 +  [#6769](https://github.com/rust-lang/rust-clippy/pull/6769)
 +* [`iter_count`]
 +  [#6791](https://github.com/rust-lang/rust-clippy/pull/6791)
 +* [`default_numeric_fallback`]
 +  [#6662](https://github.com/rust-lang/rust-clippy/pull/6662)
 +* [`bytes_nth`]
 +  [#6695](https://github.com/rust-lang/rust-clippy/pull/6695)
 +* [`filter_map_identity`]
 +  [#6685](https://github.com/rust-lang/rust-clippy/pull/6685)
 +* [`manual_map`]
 +  [#6573](https://github.com/rust-lang/rust-clippy/pull/6573)
 +
 +### Moves and Deprecations
 +
 +* Moved [`upper_case_acronyms`] to `pedantic`
 +  [#6775](https://github.com/rust-lang/rust-clippy/pull/6775)
 +* Moved [`manual_map`] to `nursery`
 +  [#6796](https://github.com/rust-lang/rust-clippy/pull/6796)
 +* Moved [`unnecessary_wraps`] to `pedantic`
 +  [#6765](https://github.com/rust-lang/rust-clippy/pull/6765)
 +* Moved [`trivial_regex`] to `nursery`
 +  [#6696](https://github.com/rust-lang/rust-clippy/pull/6696)
 +* Moved [`naive_bytecount`] to `pedantic`
 +  [#6825](https://github.com/rust-lang/rust-clippy/pull/6825)
 +* Moved [`upper_case_acronyms`] to `style`
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* Moved [`manual_map`] to `style`
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +
 +### Enhancements
 +
 +* [`disallowed_method`]: Now supports functions in addition to methods
 +  [#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
 +* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
 +  trigger the lint if there is more than one uppercase character next to each other
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* [`collapsible_match`]: Now supports block comparison with different value names
 +  [#6754](https://github.com/rust-lang/rust-clippy/pull/6754)
 +* [`unnecessary_wraps`]: Will now suggest removing unnecessary wrapped return unit type, like `Option<()>`
 +  [#6665](https://github.com/rust-lang/rust-clippy/pull/6665)
 +* Improved value usage detection in closures
 +  [#6698](https://github.com/rust-lang/rust-clippy/pull/6698)
 +
 +### False Positive Fixes
 +
 +* [`use_self`]: No longer lints in macros
 +  [#6833](https://github.com/rust-lang/rust-clippy/pull/6833)
 +* [`use_self`]: Fixed multiple false positives for: generics, associated types and derive implementations
 +  [#6179](https://github.com/rust-lang/rust-clippy/pull/6179)
 +* [`missing_inline_in_public_items`]: No longer lints for procedural macros
 +  [#6814](https://github.com/rust-lang/rust-clippy/pull/6814)
 +* [`inherent_to_string`]: No longer lints on functions with function generics
 +  [#6771](https://github.com/rust-lang/rust-clippy/pull/6771)
 +* [`doc_markdown`]: Add `OpenDNS` to the default configuration as an allowed identifier
 +  [#6783](https://github.com/rust-lang/rust-clippy/pull/6783)
 +* [`missing_panics_doc`]: No longer lints on [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html)
 +  [#6700](https://github.com/rust-lang/rust-clippy/pull/6700)
 +* [`collapsible_if`]: No longer lints on if statements with attributes
 +  [#6701](https://github.com/rust-lang/rust-clippy/pull/6701)
 +* [`match_same_arms`]: Only considers empty blocks as equal if the tokens contained are the same
 +  [#6843](https://github.com/rust-lang/rust-clippy/pull/6843)
 +* [`redundant_closure`]: Now ignores macros
 +  [#6871](https://github.com/rust-lang/rust-clippy/pull/6871)
 +* [`manual_map`]: Fixed false positives when control flow statements like `return`, `break` etc. are used
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* [`vec_init_then_push`]: Fixed false positives for loops and if statements
 +  [#6697](https://github.com/rust-lang/rust-clippy/pull/6697)
 +* [`len_without_is_empty`]: Will now consider multiple impl blocks and `#[allow]` on
 +  the `len` method as well as the type definition.
 +  [#6853](https://github.com/rust-lang/rust-clippy/pull/6853)
 +* [`let_underscore_drop`]: Only lints on types which implement `Drop`
 +  [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 +* [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
 +  [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
 +* [`cargo_common_metadata`]: No longer lints if
 +  [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
 +  is defined in the manifest
 +  [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`collapsible_match`]: Fixed lint message capitalization
 +  [#6766](https://github.com/rust-lang/rust-clippy/pull/6766)
 +* [`or_fun_call`]: Improved suggestions for `or_insert(vec![])`
 +  [#6790](https://github.com/rust-lang/rust-clippy/pull/6790)
 +* [`manual_map`]: No longer expands macros in the suggestions
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* Aligned Clippy's lint messages with the rustc dev guide
 +  [#6787](https://github.com/rust-lang/rust-clippy/pull/6787)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6866](https://github.com/rust-lang/rust-clippy/pull/6866)
 +
 +### Documentation Improvements
 +
 +* [`useless_format`]: Improved the documentation example
 +  [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
 +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
 +  [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 +
 +### Others
 +* Running `cargo clippy` after `cargo check` now works as expected
 +  (`cargo clippy` and `cargo check` no longer shares the same build cache)
 +  [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 +* Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
 +  [#6834](https://github.com/rust-lang/rust-clippy/pull/6834)
 +* Extracted Clippy's `utils` module into the new `clippy_utils` crate
 +  [#6756](https://github.com/rust-lang/rust-clippy/pull/6756)
 +* Clippy lintcheck tool improvements
 +  [#6800](https://github.com/rust-lang/rust-clippy/pull/6800)
 +  [#6735](https://github.com/rust-lang/rust-clippy/pull/6735)
 +  [#6764](https://github.com/rust-lang/rust-clippy/pull/6764)
 +  [#6708](https://github.com/rust-lang/rust-clippy/pull/6708)
 +  [#6780](https://github.com/rust-lang/rust-clippy/pull/6780)
 +  [#6686](https://github.com/rust-lang/rust-clippy/pull/6686)
 +
 +## Rust 1.51
 +
 +Released 2021-03-25
 +
 +[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 +
 +### New Lints
 +
 +* [`upper_case_acronyms`]
 +  [#6475](https://github.com/rust-lang/rust-clippy/pull/6475)
 +* [`from_over_into`] [#6476](https://github.com/rust-lang/rust-clippy/pull/6476)
 +* [`case_sensitive_file_extension_comparisons`]
 +  [#6500](https://github.com/rust-lang/rust-clippy/pull/6500)
 +* [`needless_question_mark`]
 +  [#6507](https://github.com/rust-lang/rust-clippy/pull/6507)
 +* [`missing_panics_doc`]
 +  [#6523](https://github.com/rust-lang/rust-clippy/pull/6523)
 +* [`redundant_slicing`]
 +  [#6528](https://github.com/rust-lang/rust-clippy/pull/6528)
 +* [`vec_init_then_push`]
 +  [#6538](https://github.com/rust-lang/rust-clippy/pull/6538)
 +* [`ptr_as_ptr`] [#6542](https://github.com/rust-lang/rust-clippy/pull/6542)
 +* [`collapsible_else_if`] (split out from `collapsible_if`)
 +  [#6544](https://github.com/rust-lang/rust-clippy/pull/6544)
 +* [`inspect_for_each`] [#6577](https://github.com/rust-lang/rust-clippy/pull/6577)
 +* [`manual_filter_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* [`exhaustive_enums`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +* [`exhaustive_structs`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +
 +### Moves and Deprecations
 +
 +* Replace [`find_map`] with [`manual_find_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* `unknown_clippy_lints` Now integrated in the `unknown_lints` rustc lint
 +  [#6653](https://github.com/rust-lang/rust-clippy/pull/6653)
 +
 +### Enhancements
 +
 +* [`ptr_arg`] Now also suggests to use `&Path` instead of `&PathBuf`
 +  [#6506](https://github.com/rust-lang/rust-clippy/pull/6506)
 +* [`cast_ptr_alignment`] Also lint when the `pointer::cast` method is used
 +  [#6557](https://github.com/rust-lang/rust-clippy/pull/6557)
 +* [`collapsible_match`] Now also deals with `&` and `*` operators in the `match`
 +  scrutinee [#6619](https://github.com/rust-lang/rust-clippy/pull/6619)
 +
 +### False Positive Fixes
 +
 +* [`similar_names`] Ignore underscore prefixed names
 +  [#6403](https://github.com/rust-lang/rust-clippy/pull/6403)
 +* [`print_literal`] and [`write_literal`] No longer lint numeric literals
 +  [#6408](https://github.com/rust-lang/rust-clippy/pull/6408)
 +* [`large_enum_variant`] No longer lints in external macros
 +  [#6485](https://github.com/rust-lang/rust-clippy/pull/6485)
 +* [`empty_enum`] Only lint if `never_type` feature is enabled
 +  [#6513](https://github.com/rust-lang/rust-clippy/pull/6513)
 +* [`field_reassign_with_default`] No longer lints in macros
 +  [#6553](https://github.com/rust-lang/rust-clippy/pull/6553)
 +* [`size_of_in_element_count`] No longer lints when dividing by element size
 +  [#6578](https://github.com/rust-lang/rust-clippy/pull/6578)
 +* [`needless_return`] No longer lints in macros
 +  [#6586](https://github.com/rust-lang/rust-clippy/pull/6586)
 +* [`match_overlapping_arm`] No longer lint when first arm is completely included
 +  in second arm [#6603](https://github.com/rust-lang/rust-clippy/pull/6603)
 +* [`doc_markdown`] Add `WebGL` to the default configuration as an allowed
 +  identifier [#6605](https://github.com/rust-lang/rust-clippy/pull/6605)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`field_reassign_with_default`] Don't expand macro in lint suggestion
 +  [#6531](https://github.com/rust-lang/rust-clippy/pull/6531)
 +* [`match_like_matches_macro`] Strip references in suggestion
 +  [#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
 +* [`single_match`] Suggest `if` over `if let` when possible
 +  [#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
 +* [`ref_in_deref`] Use parentheses correctly in suggestion
 +  [#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
 +* [`stable_sort_primitive`] Clarify error message
 +  [#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6582](https://github.com/rust-lang/rust-clippy/pull/6582)
 +
 +### Documentation Improvements
 +
 +* Improve search performance on the Clippy website and make it possible to
 +  directly search for lints on the GitHub issue tracker
 +  [#6483](https://github.com/rust-lang/rust-clippy/pull/6483)
 +* Clean up `README.md` by removing outdated paragraph
 +  [#6488](https://github.com/rust-lang/rust-clippy/pull/6488)
 +* [`await_holding_refcell_ref`] and [`await_holding_lock`]
 +  [#6585](https://github.com/rust-lang/rust-clippy/pull/6585)
 +* [`as_conversions`] [#6608](https://github.com/rust-lang/rust-clippy/pull/6608)
 +
 +### Others
 +
 +* Clippy now has a [Roadmap] for 2021. If you like to get involved in a bigger
 +  project, take a look at the [Roadmap project page]. All issues listed there
 +  are actively mentored
 +  [#6462](https://github.com/rust-lang/rust-clippy/pull/6462)
 +* The Clippy version number now corresponds to the Rust version number
 +  [#6526](https://github.com/rust-lang/rust-clippy/pull/6526)
 +* Fix oversight which caused Clippy to lint deps in some environments, where
 +  `CLIPPY_TESTS=true` was set somewhere
 +  [#6575](https://github.com/rust-lang/rust-clippy/pull/6575)
 +* Add `cargo dev-lintcheck` tool to the Clippy Dev Tool
 +  [#6469](https://github.com/rust-lang/rust-clippy/pull/6469)
 +
 +[Roadmap]: https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md
 +[Roadmap project page]: https://github.com/rust-lang/rust-clippy/projects/3
 +
 +## Rust 1.50
 +
 +Released 2021-02-11
 +
 +[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
 +
 +### New Lints
 +
 +* [`suspicious_operation_groupings`] [#6086](https://github.com/rust-lang/rust-clippy/pull/6086)
 +* [`size_of_in_element_count`] [#6394](https://github.com/rust-lang/rust-clippy/pull/6394)
 +* [`unnecessary_wraps`] [#6070](https://github.com/rust-lang/rust-clippy/pull/6070)
 +* [`let_underscore_drop`] [#6305](https://github.com/rust-lang/rust-clippy/pull/6305)
 +* [`collapsible_match`] [#6402](https://github.com/rust-lang/rust-clippy/pull/6402)
 +* [`redundant_else`] [#6330](https://github.com/rust-lang/rust-clippy/pull/6330)
 +* [`zero_sized_map_values`] [#6218](https://github.com/rust-lang/rust-clippy/pull/6218)
 +* [`print_stderr`] [#6367](https://github.com/rust-lang/rust-clippy/pull/6367)
 +* [`string_from_utf8_as_bytes`] [#6134](https://github.com/rust-lang/rust-clippy/pull/6134)
 +
 +### Moves and Deprecations
 +
 +* Previously deprecated [`str_to_string`] and [`string_to_string`] have been un-deprecated
 +  as `restriction` lints [#6333](https://github.com/rust-lang/rust-clippy/pull/6333)
 +* Deprecate `panic_params` lint. This is now available in rustc as `non_fmt_panics`
 +  [#6351](https://github.com/rust-lang/rust-clippy/pull/6351)
 +* Move [`map_err_ignore`] to `restriction`
 +  [#6416](https://github.com/rust-lang/rust-clippy/pull/6416)
 +* Move [`await_holding_refcell_ref`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +* Move [`await_holding_lock`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +
 +### Enhancements
 +
 +* Add the `unreadable-literal-lint-fractions` configuration to disable
 +  the `unreadable_literal` lint for fractions
 +  [#6421](https://github.com/rust-lang/rust-clippy/pull/6421)
 +* [`clone_on_copy`]: Now shows the type in the lint message
 +  [#6443](https://github.com/rust-lang/rust-clippy/pull/6443)
 +* [`redundant_pattern_matching`]: Now also lints on `std::task::Poll`
 +  [#6339](https://github.com/rust-lang/rust-clippy/pull/6339)
 +* [`redundant_pattern_matching`]: Additionally also lints on `std::net::IpAddr`
 +  [#6377](https://github.com/rust-lang/rust-clippy/pull/6377)
 +* [`search_is_some`]: Now suggests `contains` instead of `find(foo).is_some()`
 +  [#6119](https://github.com/rust-lang/rust-clippy/pull/6119)
 +* [`clone_double_ref`]: Now prints the reference type in the lint message
 +  [#6442](https://github.com/rust-lang/rust-clippy/pull/6442)
 +* [`modulo_one`]: Now also lints on -1.
 +  [#6360](https://github.com/rust-lang/rust-clippy/pull/6360)
 +* [`empty_loop`]: Now lints no_std crates, too
 +  [#6205](https://github.com/rust-lang/rust-clippy/pull/6205)
 +* [`or_fun_call`]: Now also lints when indexing `HashMap` or `BTreeMap`
 +  [#6267](https://github.com/rust-lang/rust-clippy/pull/6267)
 +* [`wrong_self_convention`]: Now also lints in trait definitions
 +  [#6316](https://github.com/rust-lang/rust-clippy/pull/6316)
 +* [`needless_borrow`]: Print the type in the lint message
 +  [#6449](https://github.com/rust-lang/rust-clippy/pull/6449)
 +
 +[msrv_readme]: https://github.com/rust-lang/rust-clippy#specifying-the-minimum-supported-rust-version
 +
 +### False Positive Fixes
 +
 +* [`manual_range_contains`]: No longer lints in `const fn`
 +  [#6382](https://github.com/rust-lang/rust-clippy/pull/6382)
 +* [`unnecessary_lazy_evaluations`]: No longer lints if closure argument is used
 +  [#6370](https://github.com/rust-lang/rust-clippy/pull/6370)
 +* [`match_single_binding`]: Now ignores cases with `#[cfg()]` macros
 +  [#6435](https://github.com/rust-lang/rust-clippy/pull/6435)
 +* [`match_like_matches_macro`]: No longer lints on arms with attributes
 +  [#6290](https://github.com/rust-lang/rust-clippy/pull/6290)
 +* [`map_clone`]: No longer lints with deref and clone
 +  [#6269](https://github.com/rust-lang/rust-clippy/pull/6269)
 +* [`map_clone`]: No longer lints in the case of &mut
 +  [#6301](https://github.com/rust-lang/rust-clippy/pull/6301)
 +* [`needless_update`]: Now ignores `non_exhaustive` structs
 +  [#6464](https://github.com/rust-lang/rust-clippy/pull/6464)
 +* [`needless_collect`]: No longer lints when a collect is needed multiple times
 +  [#6313](https://github.com/rust-lang/rust-clippy/pull/6313)
 +* [`unnecessary_cast`] No longer lints cfg-dependent types
 +  [#6369](https://github.com/rust-lang/rust-clippy/pull/6369)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
 +  Both now ignore enums with frozen variants
 +  [#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
 +* [`field_reassign_with_default`] No longer lint for private fields
 +  [#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
 +
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`vec_box`]: Provide correct type scope suggestion
 +  [#6271](https://github.com/rust-lang/rust-clippy/pull/6271)
 +* [`manual_range_contains`]: Give correct suggestion when using floats
 +  [#6320](https://github.com/rust-lang/rust-clippy/pull/6320)
 +* [`unnecessary_lazy_evaluations`]: Don't always mark suggestion as MachineApplicable
 +  [#6272](https://github.com/rust-lang/rust-clippy/pull/6272)
 +* [`manual_async_fn`]: Improve suggestion formatting
 +  [#6294](https://github.com/rust-lang/rust-clippy/pull/6294)
 +* [`unnecessary_cast`]: Fix incorrectly formatted float literal suggestion
 +  [#6362](https://github.com/rust-lang/rust-clippy/pull/6362)
 +
 +### ICE Fixes
 +
 +* Fix a crash in [`from_iter_instead_of_collect`]
 +  [#6304](https://github.com/rust-lang/rust-clippy/pull/6304)
 +* Fix a silent crash when parsing doc comments in [`needless_doctest_main`]
 +  [#6458](https://github.com/rust-lang/rust-clippy/pull/6458)
 +
 +### Documentation Improvements
 +
 +* The lint website search has been improved ([#6477](https://github.com/rust-lang/rust-clippy/pull/6477)):
 +  * Searching for lints with dashes and spaces is possible now. For example
 +    `missing-errors-doc` and `missing errors doc` are now valid aliases for lint names
 +  * Improved fuzzy search in lint descriptions
 +* Various README improvements
 +  [#6287](https://github.com/rust-lang/rust-clippy/pull/6287)
 +* Add known problems to [`comparison_chain`] documentation
 +  [#6390](https://github.com/rust-lang/rust-clippy/pull/6390)
 +* Fix example used in [`cargo_common_metadata`]
 +  [#6293](https://github.com/rust-lang/rust-clippy/pull/6293)
 +* Improve [`map_clone`] documentation
 +  [#6340](https://github.com/rust-lang/rust-clippy/pull/6340)
 +
 +### Others
 +
 +* You can now tell Clippy about the MSRV your project supports. Please refer to
 +  the specific README section to learn more about MSRV support [here][msrv_readme]
 +  [#6201](https://github.com/rust-lang/rust-clippy/pull/6201)
 +* Add `--no-deps` option to avoid running on path dependencies in workspaces
 +  [#6188](https://github.com/rust-lang/rust-clippy/pull/6188)
 +
 +## Rust 1.49
 +
 +Released 2020-12-31
 +
 +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 +
 +### New Lints
 +
 +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
 +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
 +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
 +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
 +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
 +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
 +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
 +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
 +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
 +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
 +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
 +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
 +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
 +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
 +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
 +
 +### Moves and Deprecations
 +
 +* Rename `single_char_push_str` to [`single_char_add_str`]
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* Rename `zero_width_space` to [`invisible_characters`]
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* Deprecate `drop_bounds` (uplifted)
 +  [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
 +* Move [`string_lit_as_bytes`] to `nursery`
 +  [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
 +* Move [`rc_buffer`] to `restriction`
 +  [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
 +
 +### Enhancements
 +
 +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
 +  reliable suggestion)
 +  [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
 +* [`single_char_add_str`]: Also lint on `String::insert_str`
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* [`eq_op`]: Also lint on the `assert_*!` macro family
 +  [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
 +* [`items_after_statements`]: Also lint in local macro expansions
 +  [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
 +* [`unnecessary_cast`]: Also lint casts on integer and float literals
 +  [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
 +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
 +  [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
 +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
 +  [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
 +* [`integer_arithmetic`]: Better handle `/` an `%` operators
 +  [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
 +
 +### False Positive Fixes
 +
 +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
 +  lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
 +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
 +  is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
 +* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
 +  [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
 +* [`needless_range_loop`]: No longer lints, when the iterable is used in the
 +  range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
 +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
 +  [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
 +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
 +  float (e.g. `713.32_64`)
 +  [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
 +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
 +  [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
 +* [`boxed_local`]: No longer lints on `extern fn` arguments
 +  [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
 +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
 +  clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
 +  [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
 +* [`needless_arbitrary_self_type`]: Correctly handle expanded code
 +  [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
 +* [`useless_format`]: Preserve raw strings in suggestion
 +  [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
 +* [`empty_loop`]: Suggest alternatives
 +  [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`borrowed_box`]: Correctly add parentheses in suggestion
 +  [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
 +* [`unused_unit`]: Improve suggestion formatting
 +  [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
 +
 +### Documentation Improvements
 +
 +* Some doc improvements:
 +    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
 +    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`doc_markdown`]: Document problematic link text style
 +  [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 +
 +## Rust 1.48
 +
 +Released 2020-11-19
 +
 +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 +
 +### New lints
 +
 +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
 +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
 +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
 +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 +* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
 +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`verbose_bit_mask`] to pedantic
 +  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
 +
 +### Enhancements
 +
 +* Extend [`precedence`] to handle chains of methods combined with unary negation
 +  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
 +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
 +  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
 +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
 +  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
 +* `invalid_atomic_ordering`: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
 +  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
 +* Avoid [`redundant_pattern_matching`] triggering in macros
 +  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
 +* [`option_if_let_else`]: distinguish pure from impure `else` expressions
 +  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
 +* [`needless_doctest_main`]: parse doctests instead of using textual search
 +  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
 +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
 +  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
 +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
 +  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
 +
 +### False Positive Fixes
 +
 +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
 +  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
 +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
 +  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
 +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
 +  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
 +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
 +  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
 +* [`doc_markdown`]: allow using "GraphQL" without backticks
 +  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
 +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
 +  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
 +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
 +  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
 +* [`should_implement_trait`]: ignore methods with lifetime parameters
 +  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
 +* [`needless_return`]: avoid linting if a temporary borrows a local variable
 +  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
 +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
 +  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
 +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
 +  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
 +  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
 +  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
 +* [`useless_conversion`]: show the type in the error message
 +  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
 +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
 +  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
 +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
 +  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
 +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
 +  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
 +* [`collapsible_if`]: don't use expanded code in the suggestion
 +  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
 +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
 +  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
 +* [`unit_arg`]: improve the readability of the suggestion
 +  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
 +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
 +  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
 +* Show line count and max lines in [`too_many_lines`] lint message
 +  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
 +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
 +  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
 +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
 +  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
 +* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
 +  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
 +* Make lint messages adhere to rustc dev guide conventions
 +  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`repeat_once`]
 +  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
 +
 +### Documentation Improvements
 +
 +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
 +  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
 +* [`unnecessary_mut_passed`]: fix typo
 +  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
 +* Add example of false positive to [`ptr_arg`] docs.
 +  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
 +* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
 +  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 +
 +## Rust 1.47
 +
 +Released 2020-10-08
 +
 +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 +
 +### New lints
 +
 +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
 +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
 +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
 +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
 +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
 +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
 +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
 +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
 +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
 +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
 +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
 +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`regex_macro`] lint
 +  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
 +* Move [`range_minus_one`] to `pedantic`
 +  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
 +
 +### Enhancements
 +
 +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
 +  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
 +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
 +  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
 +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
 +  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
 +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
 +  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
 +* Make it possible to allow [`unsafe_derive_deserialize`]
 +  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
 +* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
 +  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
 +* Make [`clone_on_copy`] suggestion machine applicable
 +  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
 +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +
 +### False Positive Fixes
 +
 +* Avoid triggering [`or_fun_call`] with const fns that take no arguments
 +  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
 +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
 +  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
 +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
 +  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
 +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
 +  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
 +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
 +  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
 +* Avoid linting if key borrows in [`unnecessary_sort_by`]
 +  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
 +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
 +  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
 +* Take input lifetimes into account in `manual_async_fn`
 +  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
 +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
 +  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
 +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
 +  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
 +  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
 +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
 +  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
 +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
 +  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
 +* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
 +  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
 +* Add suggestion for [`iter_skip_next`]
 +  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
 +* Improve [`collapsible_if`] fix suggestion
 +  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused by [`needless_collect`]
 +  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
 +* Fix ICE caused by [`unnested_or_patterns`]
 +  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
 +
 +### Documentation Improvements
 +
 +* Fix grammar of [`await_holding_lock`] documentation
 +  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
 +
 +### Others
 +
 +* Make lints adhere to the rustc dev guide
 +  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 +
 +## Rust 1.46
 +
 +Released 2020-08-27
 +
 +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 +
 +### New lints
 +
 +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
 +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
 +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
 +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
 +
 +### Moves and Deprecations
 +
 +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
 +
 +### Enhancements
 +
 +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
 +
 +### False Positive Fixes
 +
 +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
 +  [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
 +* [`let_and_return`]: Don't lint if a temporary borrow is involved
 +  [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
 +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
 +  [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 +* [`if_same_then_else`]: Don't assume multiplication is always commutative
 +  [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
 +* [`blacklisted_name`]: Remove `bar` from the default configuration
 +  [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
 +  [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
 +  [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
 +* Add auto applicable suggestion to [`macro_use_imports`]
 +  [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
 +
 +### ICE Fixes
 +
 +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
 +
 +### Documentation Improvements
 +
 +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
 +
 +### Others
 +
 +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
 +  into `rustc` and passes all the given arguments to `rustc`. This is especially
 +  useful for tools that need the `rustc` version Clippy was compiled with,
 +  instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
 +  print the output of `rustc --version`.
 +  [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
 +* New issue templates now make it easier to complain if Clippy is too annoying
 +  or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
 +
 +## Rust 1.45
 +
 +Released 2020-07-16
 +
 +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 +
 +### New lints
 +
 +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
 +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
 +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
 +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
 +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
 +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
 +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
 +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
 +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
 +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
 +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
 +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
 +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
 +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +
 +### Enhancements
 +
 +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
 +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
 +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
 +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
 +
 +### False Positive Fixes
 +
 +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
 +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
 +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
 +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
 +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
 +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
 +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
 +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
 +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
 +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
 +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
 +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
 +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
 +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
 +
 +### Suggestion Improvements
 +
 +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
 +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
 +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
 +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
 +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
 +
 +### Documentation
 +
 +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
 +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 +
 +## Rust 1.44
 +
 +Released 2020-06-04
 +
 +[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 +
 +### New lints
 +
 +* [`explicit_deref_methods`] [#5226](https://github.com/rust-lang/rust-clippy/pull/5226)
 +* [`implicit_saturating_sub`] [#5427](https://github.com/rust-lang/rust-clippy/pull/5427)
 +* [`macro_use_imports`] [#5230](https://github.com/rust-lang/rust-clippy/pull/5230)
 +* [`verbose_file_reads`] [#5272](https://github.com/rust-lang/rust-clippy/pull/5272)
 +* [`future_not_send`] [#5423](https://github.com/rust-lang/rust-clippy/pull/5423)
 +* [`redundant_pub_crate`] [#5319](https://github.com/rust-lang/rust-clippy/pull/5319)
 +* [`large_const_arrays`] [#5248](https://github.com/rust-lang/rust-clippy/pull/5248)
 +* [`result_map_or_into_option`] [#5415](https://github.com/rust-lang/rust-clippy/pull/5415)
 +* [`redundant_allocation`] [#5349](https://github.com/rust-lang/rust-clippy/pull/5349)
 +* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
 +* Move [`cognitive_complexity`] to nursery [#5428](https://github.com/rust-lang/rust-clippy/pull/5428)
 +* Move [`useless_transmute`] to nursery [#5364](https://github.com/rust-lang/rust-clippy/pull/5364)
 +* Downgrade [`inefficient_to_string`] to pedantic [#5412](https://github.com/rust-lang/rust-clippy/pull/5412)
 +* Downgrade [`option_option`] to pedantic [#5401](https://github.com/rust-lang/rust-clippy/pull/5401)
 +* Downgrade [`unreadable_literal`] to pedantic [#5419](https://github.com/rust-lang/rust-clippy/pull/5419)
 +* Downgrade [`let_unit_value`] to pedantic [#5409](https://github.com/rust-lang/rust-clippy/pull/5409)
 +* Downgrade [`trivially_copy_pass_by_ref`] to pedantic [#5410](https://github.com/rust-lang/rust-clippy/pull/5410)
 +* Downgrade [`implicit_hasher`] to pedantic [#5411](https://github.com/rust-lang/rust-clippy/pull/5411)
 +
 +### Enhancements
 +
 +* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
 +  auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 +* Make [`redundant_clone`] also trigger on cases where the cloned value is not
 +  consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
 +* Expand [`integer_arithmetic`] to also disallow bit-shifting [#5430](https://github.com/rust-lang/rust-clippy/pull/5430)
 +* [`option_as_ref_deref`] now detects more deref cases [#5425](https://github.com/rust-lang/rust-clippy/pull/5425)
 +* [`large_enum_variant`] now report the sizes of the largest and second-largest variants [#5466](https://github.com/rust-lang/rust-clippy/pull/5466)
 +* [`bool_comparison`] now also checks for inequality comparisons that can be
 +  written more concisely [#5365](https://github.com/rust-lang/rust-clippy/pull/5365)
 +* Expand [`clone_on_copy`] to work in method call arguments as well [#5441](https://github.com/rust-lang/rust-clippy/pull/5441)
 +* [`redundant_pattern_matching`] now also handles `while let` [#5483](https://github.com/rust-lang/rust-clippy/pull/5483)
 +* [`integer_arithmetic`] now also lints references of integers [#5329](https://github.com/rust-lang/rust-clippy/pull/5329)
 +* Expand [`float_cmp_const`] to also work on arrays [#5345](https://github.com/rust-lang/rust-clippy/pull/5345)
 +* Trigger [`map_flatten`] when map is called on an `Option` [#5473](https://github.com/rust-lang/rust-clippy/pull/5473)
 +
 +### False Positive Fixes
 +
 +* [`many_single_char_names`] [#5468](https://github.com/rust-lang/rust-clippy/pull/5468)
 +* [`should_implement_trait`] [#5437](https://github.com/rust-lang/rust-clippy/pull/5437)
 +* [`unused_self`] [#5387](https://github.com/rust-lang/rust-clippy/pull/5387)
 +* [`redundant_clone`] [#5453](https://github.com/rust-lang/rust-clippy/pull/5453)
 +* [`precedence`] [#5445](https://github.com/rust-lang/rust-clippy/pull/5445)
 +* [`suspicious_op_assign_impl`] [#5424](https://github.com/rust-lang/rust-clippy/pull/5424)
 +* [`needless_lifetimes`] [#5293](https://github.com/rust-lang/rust-clippy/pull/5293)
 +* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 +* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 +
 +
 +### Suggestion Improvements
 +
 +* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
 +* Improve the suggested placeholder in [`option_map_unit_fn`] [#5292](https://github.com/rust-lang/rust-clippy/pull/5292)
 +* Improve suggestion for [`match_single_binding`] when triggered inside a closure [#5350](https://github.com/rust-lang/rust-clippy/pull/5350)
 +
 +### ICE Fixes
 +
 +* Handle the unstable `trivial_bounds` feature [#5296](https://github.com/rust-lang/rust-clippy/pull/5296)
 +* `shadow_*` lints [#5297](https://github.com/rust-lang/rust-clippy/pull/5297)
 +
 +### Documentation
 +
 +* Fix documentation generation for configurable lints [#5353](https://github.com/rust-lang/rust-clippy/pull/5353)
 +* Update documentation for [`new_ret_no_self`] [#5448](https://github.com/rust-lang/rust-clippy/pull/5448)
 +* The documentation for [`option_option`] now suggest using a tri-state enum [#5403](https://github.com/rust-lang/rust-clippy/pull/5403)
 +* Fix bit mask example in [`verbose_bit_mask`] documentation [#5454](https://github.com/rust-lang/rust-clippy/pull/5454)
 +* [`wildcard_imports`] documentation now mentions that `use ...::prelude::*` is
 +  not linted [#5312](https://github.com/rust-lang/rust-clippy/pull/5312)
 +
 +## Rust 1.43
 +
 +Released 2020-04-23
 +
 +[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 +
 +### New lints
 +
 +* [`imprecise_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`suboptimal_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`wildcard_imports`] [#5029](https://github.com/rust-lang/rust-clippy/pull/5029)
 +* [`single_component_path_imports`] [#5058](https://github.com/rust-lang/rust-clippy/pull/5058)
 +* [`match_single_binding`] [#5061](https://github.com/rust-lang/rust-clippy/pull/5061)
 +* [`let_underscore_lock`] [#5101](https://github.com/rust-lang/rust-clippy/pull/5101)
 +* [`struct_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`fn_params_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`option_env_unwrap`] [#5148](https://github.com/rust-lang/rust-clippy/pull/5148)
 +* [`lossy_float_literal`] [#5202](https://github.com/rust-lang/rust-clippy/pull/5202)
 +* [`rest_pat_in_fully_bound_structs`] [#5258](https://github.com/rust-lang/rust-clippy/pull/5258)
 +
 +### Moves and Deprecations
 +
 +* Move [`unneeded_field_pattern`] to pedantic group [#5200](https://github.com/rust-lang/rust-clippy/pull/5200)
 +
 +### Enhancements
 +
 +* Make [`missing_errors_doc`] lint also trigger on `async` functions
 +  [#5181](https://github.com/rust-lang/rust-clippy/pull/5181)
 +* Add more constants to [`approx_constant`] [#5193](https://github.com/rust-lang/rust-clippy/pull/5193)
 +* Extend [`question_mark`] lint [#5266](https://github.com/rust-lang/rust-clippy/pull/5266)
 +
 +### False Positive Fixes
 +
 +* [`use_debug`] [#5047](https://github.com/rust-lang/rust-clippy/pull/5047)
 +* [`unnecessary_unwrap`] [#5132](https://github.com/rust-lang/rust-clippy/pull/5132)
 +* [`zero_prefixed_literal`] [#5170](https://github.com/rust-lang/rust-clippy/pull/5170)
 +* [`missing_const_for_fn`] [#5216](https://github.com/rust-lang/rust-clippy/pull/5216)
 +
 +### Suggestion Improvements
 +
 +* Improve suggestion when blocks of code are suggested [#5134](https://github.com/rust-lang/rust-clippy/pull/5134)
 +
 +### ICE Fixes
 +
 +* `misc_early` lints [#5129](https://github.com/rust-lang/rust-clippy/pull/5129)
 +* [`missing_errors_doc`] [#5213](https://github.com/rust-lang/rust-clippy/pull/5213)
 +* Fix ICE when evaluating `usize`s [#5256](https://github.com/rust-lang/rust-clippy/pull/5256)
 +
 +### Documentation
 +
 +* Improve documentation of [`iter_nth_zero`]
 +* Add documentation pages for stable releases [#5171](https://github.com/rust-lang/rust-clippy/pull/5171)
 +
 +### Others
 +
 +* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 +
 +
 +## Rust 1.42
 +
 +Released 2020-03-12
 +
 +[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206)
 +
 +### New lints
 +
 +* [`filetype_is_file`] [#4543](https://github.com/rust-lang/rust-clippy/pull/4543)
 +* [`let_underscore_must_use`] [#4823](https://github.com/rust-lang/rust-clippy/pull/4823)
 +* [`modulo_arithmetic`] [#4867](https://github.com/rust-lang/rust-clippy/pull/4867)
 +* [`mem_replace_with_default`] [#4881](https://github.com/rust-lang/rust-clippy/pull/4881)
 +* [`mutable_key_type`] [#4885](https://github.com/rust-lang/rust-clippy/pull/4885)
 +* [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945)
 +* [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960)
 +* [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966)
 +* `invalid_atomic_ordering` [#4999](https://github.com/rust-lang/rust-clippy/pull/4999)
 +* [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067)
 +
 +### Moves and Deprecations
 +
 +* Move [`transmute_float_to_int`] from nursery to complexity group
 +  [#5015](https://github.com/rust-lang/rust-clippy/pull/5015)
 +* Move [`range_plus_one`] to pedantic group [#5057](https://github.com/rust-lang/rust-clippy/pull/5057)
 +* Move [`debug_assert_with_mut_call`] to nursery group [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Deprecate `unused_label` [#4930](https://github.com/rust-lang/rust-clippy/pull/4930)
 +
 +### Enhancements
 +
 +* Lint vectored IO in [`unused_io_amount`] [#5027](https://github.com/rust-lang/rust-clippy/pull/5027)
 +* Make [`vec_box`] configurable by adding a size threshold [#5081](https://github.com/rust-lang/rust-clippy/pull/5081)
 +* Also lint constants in [`cmp_nan`] [#4910](https://github.com/rust-lang/rust-clippy/pull/4910)
 +* Fix false negative in [`expect_fun_call`] [#4915](https://github.com/rust-lang/rust-clippy/pull/4915)
 +* Fix false negative in [`redundant_clone`] [#5017](https://github.com/rust-lang/rust-clippy/pull/5017)
 +
 +### False Positive Fixes
 +
 +* [`map_clone`] [#4937](https://github.com/rust-lang/rust-clippy/pull/4937)
 +* [`replace_consts`] [#4977](https://github.com/rust-lang/rust-clippy/pull/4977)
 +* [`let_and_return`] [#5008](https://github.com/rust-lang/rust-clippy/pull/5008)
 +* [`eq_op`] [#5079](https://github.com/rust-lang/rust-clippy/pull/5079)
 +* [`possible_missing_comma`] [#5083](https://github.com/rust-lang/rust-clippy/pull/5083)
 +* [`debug_assert_with_mut_call`] [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Don't trigger [`let_underscore_must_use`] in external macros
 +  [#5082](https://github.com/rust-lang/rust-clippy/pull/5082)
 +* Don't trigger [`empty_loop`] in `no_std` crates [#5086](https://github.com/rust-lang/rust-clippy/pull/5086)
 +
 +### Suggestion Improvements
 +
 +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634)
 +* [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934)
 +* [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935)
 +* [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956)
 +* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
 +* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
 +* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
 +* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
 +
 +### ICE fixes
 +
 +* [`unsound_collection_transmute`] [#4975](https://github.com/rust-lang/rust-clippy/pull/4975)
 +
 +### Documentation
 +
 +* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 +
 +
 +## Rust 1.41
 +
 +Released 2020-01-30
 +
 +[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7)
 +
 +* New Lints:
 +  * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
 +  * [`to_digit_is_some`] [#4801](https://github.com/rust-lang/rust-clippy/pull/4801)
 +  * [`tabs_in_doc_comments`] [#4806](https://github.com/rust-lang/rust-clippy/pull/4806)
 +  * [`large_stack_arrays`] [#4807](https://github.com/rust-lang/rust-clippy/pull/4807)
 +  * [`same_functions_in_if_condition`] [#4814](https://github.com/rust-lang/rust-clippy/pull/4814)
 +  * [`zst_offset`] [#4816](https://github.com/rust-lang/rust-clippy/pull/4816)
 +  * [`as_conversions`] [#4821](https://github.com/rust-lang/rust-clippy/pull/4821)
 +  * [`missing_errors_doc`] [#4884](https://github.com/rust-lang/rust-clippy/pull/4884)
 +  * [`transmute_float_to_int`] [#4889](https://github.com/rust-lang/rust-clippy/pull/4889)
 +* Remove plugin interface, see
 +  [Inside Rust Blog](https://blog.rust-lang.org/inside-rust/2019/11/04/Clippy-removes-plugin-interface.html) for
 +  details [#4714](https://github.com/rust-lang/rust-clippy/pull/4714)
 +* Move [`use_self`] to nursery group [#4863](https://github.com/rust-lang/rust-clippy/pull/4863)
 +* Deprecate `into_iter_on_array` [#4788](https://github.com/rust-lang/rust-clippy/pull/4788)
 +* Expand [`string_lit_as_bytes`] to also trigger when literal has escapes
 +  [#4808](https://github.com/rust-lang/rust-clippy/pull/4808)
 +* Fix false positive in `comparison_chain` [#4842](https://github.com/rust-lang/rust-clippy/pull/4842)
 +* Fix false positive in `while_immutable_condition` [#4730](https://github.com/rust-lang/rust-clippy/pull/4730)
 +* Fix false positive in `explicit_counter_loop` [#4803](https://github.com/rust-lang/rust-clippy/pull/4803)
 +* Fix false positive in `must_use_candidate` [#4794](https://github.com/rust-lang/rust-clippy/pull/4794)
 +* Fix false positive in `print_with_newline` and `write_with_newline`
 +  [#4769](https://github.com/rust-lang/rust-clippy/pull/4769)
 +* Fix false positive in `derive_hash_xor_eq` [#4766](https://github.com/rust-lang/rust-clippy/pull/4766)
 +* Fix false positive in `missing_inline_in_public_items` [#4870](https://github.com/rust-lang/rust-clippy/pull/4870)
 +* Fix false positive in `string_add` [#4880](https://github.com/rust-lang/rust-clippy/pull/4880)
 +* Fix false positive in `float_arithmetic` [#4851](https://github.com/rust-lang/rust-clippy/pull/4851)
 +* Fix false positive in `cast_sign_loss` [#4883](https://github.com/rust-lang/rust-clippy/pull/4883)
 +* Fix false positive in `manual_swap` [#4877](https://github.com/rust-lang/rust-clippy/pull/4877)
 +* Fix ICEs occurring while checking some block expressions [#4772](https://github.com/rust-lang/rust-clippy/pull/4772)
 +* Fix ICE in `use_self` [#4776](https://github.com/rust-lang/rust-clippy/pull/4776)
 +* Fix ICEs related to `const_generics` [#4780](https://github.com/rust-lang/rust-clippy/pull/4780)
 +* Display help when running `clippy-driver` without arguments, instead of ICEing
 +  [#4810](https://github.com/rust-lang/rust-clippy/pull/4810)
 +* Clippy has its own ICE message now [#4588](https://github.com/rust-lang/rust-clippy/pull/4588)
 +* Show deprecated lints in the documentation again [#4757](https://github.com/rust-lang/rust-clippy/pull/4757)
 +* Improve Documentation by adding positive examples to some lints
 +  [#4832](https://github.com/rust-lang/rust-clippy/pull/4832)
 +
 +## Rust 1.40
 +
 +Released 2019-12-19
 +
 +[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb)
 +
 +* New Lints:
 +  * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
 +  * [`needless_doctest_main`] [#4603](https://github.com/rust-lang/rust-clippy/pull/4603)
 +  * [`suspicious_unary_op_formatting`] [#4615](https://github.com/rust-lang/rust-clippy/pull/4615)
 +  * [`debug_assert_with_mut_call`] [#4680](https://github.com/rust-lang/rust-clippy/pull/4680)
 +  * [`unused_self`] [#4619](https://github.com/rust-lang/rust-clippy/pull/4619)
 +  * [`inefficient_to_string`] [#4683](https://github.com/rust-lang/rust-clippy/pull/4683)
 +  * [`must_use_unit`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`must_use_candidate`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`double_must_use`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`comparison_chain`] [#4569](https://github.com/rust-lang/rust-clippy/pull/4569)
 +  * [`unsound_collection_transmute`] [#4592](https://github.com/rust-lang/rust-clippy/pull/4592)
 +  * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +* Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736)
 +* Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613)
 +* Expand `integer_arithmetic` to also detect mutating arithmetic like `+=` [#4585](https://github.com/rust-lang/rust-clippy/pull/4585)
 +* Fix false positive in `nonminimal_bool` [#4568](https://github.com/rust-lang/rust-clippy/pull/4568)
 +* Fix false positive in `missing_safety_doc` [#4611](https://github.com/rust-lang/rust-clippy/pull/4611)
 +* Fix false positive in `cast_sign_loss` [#4614](https://github.com/rust-lang/rust-clippy/pull/4614)
 +* Fix false positive in `redundant_clone` [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Fix false positive in `try_err` [#4721](https://github.com/rust-lang/rust-clippy/pull/4721)
 +* Fix false positive in `toplevel_ref_arg` [#4570](https://github.com/rust-lang/rust-clippy/pull/4570)
 +* Fix false positive in `multiple_inherent_impl` [#4593](https://github.com/rust-lang/rust-clippy/pull/4593)
 +* Improve more suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4575](https://github.com/rust-lang/rust-clippy/pull/4575)
 +* Improve suggestion for `zero_ptr` [#4599](https://github.com/rust-lang/rust-clippy/pull/4599)
 +* Improve suggestion for `explicit_counter_loop` [#4691](https://github.com/rust-lang/rust-clippy/pull/4691)
 +* Improve suggestion for `mul_add` [#4602](https://github.com/rust-lang/rust-clippy/pull/4602)
 +* Improve suggestion for `assertions_on_constants` [#4635](https://github.com/rust-lang/rust-clippy/pull/4635)
 +* Fix ICE in `use_self` [#4671](https://github.com/rust-lang/rust-clippy/pull/4671)
 +* Fix ICE when encountering const casts [#4590](https://github.com/rust-lang/rust-clippy/pull/4590)
 +
 +## Rust 1.39
 +
 +Released 2019-11-07
 +
 +[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b)
 +
 +* New Lints:
 +  * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
 +  * [`flat_map_identity`] [#4231](https://github.com/rust-lang/rust-clippy/pull/4231)
 +  * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535)
 +  * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511)
 +  * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394)
 +  * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386)
 +  * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498)
 +* Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348)
 +* Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403)
 +* Move `cast_lossless` to pedantic group [#4539](https://github.com/rust-lang/rust-clippy/pull/4539)
 +* `temporary_cstring_as_ptr` now catches more cases [#4425](https://github.com/rust-lang/rust-clippy/pull/4425)
 +* `use_self` now works in constructors, too [#4525](https://github.com/rust-lang/rust-clippy/pull/4525)
 +* `cargo_common_metadata` now checks for license files [#4518](https://github.com/rust-lang/rust-clippy/pull/4518)
 +* `cognitive_complexity` now includes the measured complexity in the warning message [#4469](https://github.com/rust-lang/rust-clippy/pull/4469)
 +* Fix false positives in `block_in_if_*` lints [#4458](https://github.com/rust-lang/rust-clippy/pull/4458)
 +* Fix false positive in `cast_lossless` [#4473](https://github.com/rust-lang/rust-clippy/pull/4473)
 +* Fix false positive in `clone_on_copy` [#4411](https://github.com/rust-lang/rust-clippy/pull/4411)
 +* Fix false positive in `deref_addrof` [#4487](https://github.com/rust-lang/rust-clippy/pull/4487)
 +* Fix false positive in `too_many_lines` [#4490](https://github.com/rust-lang/rust-clippy/pull/4490)
 +* Fix false positive in `new_ret_no_self` [#4365](https://github.com/rust-lang/rust-clippy/pull/4365)
 +* Fix false positive in `manual_swap` [#4478](https://github.com/rust-lang/rust-clippy/pull/4478)
 +* Fix false positive in `missing_const_for_fn` [#4450](https://github.com/rust-lang/rust-clippy/pull/4450)
 +* Fix false positive in `extra_unused_lifetimes` [#4477](https://github.com/rust-lang/rust-clippy/pull/4477)
 +* Fix false positive in `inherent_to_string` [#4460](https://github.com/rust-lang/rust-clippy/pull/4460)
 +* Fix false positive in `map_entry` [#4495](https://github.com/rust-lang/rust-clippy/pull/4495)
 +* Fix false positive in `unused_unit` [#4445](https://github.com/rust-lang/rust-clippy/pull/4445)
 +* Fix false positive in `redundant_pattern` [#4489](https://github.com/rust-lang/rust-clippy/pull/4489)
 +* Fix false positive in `wrong_self_convention` [#4369](https://github.com/rust-lang/rust-clippy/pull/4369)
 +* Improve various suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4558](https://github.com/rust-lang/rust-clippy/pull/4558)
 +* Improve suggestions for `redundant_pattern_matching` [#4352](https://github.com/rust-lang/rust-clippy/pull/4352)
 +* Improve suggestions for `explicit_write` [#4544](https://github.com/rust-lang/rust-clippy/pull/4544)
 +* Improve suggestion for `or_fun_call` [#4522](https://github.com/rust-lang/rust-clippy/pull/4522)
 +* Improve suggestion for `match_as_ref` [#4446](https://github.com/rust-lang/rust-clippy/pull/4446)
 +* Improve suggestion for `unnecessary_fold_span` [#4382](https://github.com/rust-lang/rust-clippy/pull/4382)
 +* Add suggestions for `unseparated_literal_suffix` [#4401](https://github.com/rust-lang/rust-clippy/pull/4401)
 +* Add suggestions for `char_lit_as_u8` [#4418](https://github.com/rust-lang/rust-clippy/pull/4418)
 +
 +## Rust 1.38
 +
 +Released 2019-09-26
 +
 +[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860)
 +
 +* New Lints:
 +  * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
 +  * [`inherent_to_string`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`inherent_to_string_shadow_display`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`type_repetition_in_bounds`] [#3766](https://github.com/rust-lang/rust-clippy/pull/3766)
 +  * [`try_err`] [#4222](https://github.com/rust-lang/rust-clippy/pull/4222)
 +* Move `{unnnecessary,panicking}_unwrap` out of nursery [#4307](https://github.com/rust-lang/rust-clippy/pull/4307)
 +* Extend the `use_self` lint to suggest uses of `Self::Variant` [#4308](https://github.com/rust-lang/rust-clippy/pull/4308)
 +* Improve suggestion for needless return [#4262](https://github.com/rust-lang/rust-clippy/pull/4262)
 +* Add auto-fixable suggestion for `let_unit` [#4337](https://github.com/rust-lang/rust-clippy/pull/4337)
 +* Fix false positive in `pub_enum_variant_names` and `enum_variant_names` [#4345](https://github.com/rust-lang/rust-clippy/pull/4345)
 +* Fix false positive in `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Fix false positive in `string_lit_as_bytes` [#4233](https://github.com/rust-lang/rust-clippy/pull/4233)
 +* Fix false positive in `needless_lifetimes` [#4266](https://github.com/rust-lang/rust-clippy/pull/4266)
 +* Fix false positive in `float_cmp` [#4275](https://github.com/rust-lang/rust-clippy/pull/4275)
 +* Fix false positives in `needless_return` [#4274](https://github.com/rust-lang/rust-clippy/pull/4274)
 +* Fix false negative in `match_same_arms` [#4246](https://github.com/rust-lang/rust-clippy/pull/4246)
 +* Fix incorrect suggestion for `needless_bool` [#4335](https://github.com/rust-lang/rust-clippy/pull/4335)
 +* Improve suggestion for `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Improve suggestion for `single_char_literal` [#4361](https://github.com/rust-lang/rust-clippy/pull/4361)
 +* Improve suggestion for `len_zero` [#4314](https://github.com/rust-lang/rust-clippy/pull/4314)
 +* Fix ICE in `implicit_hasher` [#4268](https://github.com/rust-lang/rust-clippy/pull/4268)
 +* Fix allow bug in `trivially_copy_pass_by_ref` [#4250](https://github.com/rust-lang/rust-clippy/pull/4250)
 +
 +## Rust 1.37
 +
 +Released 2019-08-15
 +
 +[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e)
 +
 +* New Lints:
 +  * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
 +  * [`get_last_with_len`] [#3832](https://github.com/rust-lang/rust-clippy/pull/3832)
 +  * [`integer_division`] [#4195](https://github.com/rust-lang/rust-clippy/pull/4195)
 +* Renamed Lint: `const_static_lifetime` is now called [`redundant_static_lifetimes`].
 +  The lint now covers statics in addition to consts [#4162](https://github.com/rust-lang/rust-clippy/pull/4162)
 +* [`match_same_arms`] now warns for all identical arms, instead of only the first one [#4102](https://github.com/rust-lang/rust-clippy/pull/4102)
 +* [`needless_return`] now works with void functions [#4220](https://github.com/rust-lang/rust-clippy/pull/4220)
 +* Fix false positive in [`redundant_closure`] [#4190](https://github.com/rust-lang/rust-clippy/pull/4190)
 +* Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107)
 +* Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214)
 +* Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136)
 +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164)
 +* Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119)
 +* Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137)
 +* Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071)
 +* Add macro check for [`unreadable_literal`] [#4099](https://github.com/rust-lang/rust-clippy/pull/4099)
 +
 +## Rust 1.36
 +
 +Released 2019-07-04
 +
 +[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7)
 +
 +* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
 +* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
 +* Move `path_buf_push_overwrite` to the nursery [#4013](https://github.com/rust-lang/rust-clippy/pull/4013)
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Allow allowing of [`toplevel_ref_arg`] lint [#4007](https://github.com/rust-lang/rust-clippy/pull/4007)
 +* Fix false negative in [`or_fun_call`] pertaining to nested constructors [#4084](https://github.com/rust-lang/rust-clippy/pull/4084)
 +* Fix false positive in [`or_fun_call`] pertaining to enum variant constructors [#4018](https://github.com/rust-lang/rust-clippy/pull/4018)
 +* Fix false positive in [`useless_let_if_seq`] pertaining to interior mutability [#4035](https://github.com/rust-lang/rust-clippy/pull/4035)
 +* Fix false positive in [`redundant_closure`] pertaining to non-function types [#4008](https://github.com/rust-lang/rust-clippy/pull/4008)
 +* Fix false positive in [`let_and_return`] pertaining to attributes on `let`s [#4024](https://github.com/rust-lang/rust-clippy/pull/4024)
 +* Fix false positive in [`module_name_repetitions`] lint pertaining to attributes [#4006](https://github.com/rust-lang/rust-clippy/pull/4006)
 +* Fix false positive on [`assertions_on_constants`] pertaining to `debug_assert!` [#3989](https://github.com/rust-lang/rust-clippy/pull/3989)
 +* Improve suggestion in [`map_clone`] to suggest `.copied()` where applicable  [#3970](https://github.com/rust-lang/rust-clippy/pull/3970) [#4043](https://github.com/rust-lang/rust-clippy/pull/4043)
 +* Improve suggestion for [`search_is_some`] [#4049](https://github.com/rust-lang/rust-clippy/pull/4049)
 +* Improve suggestion applicability for [`naive_bytecount`] [#3984](https://github.com/rust-lang/rust-clippy/pull/3984)
 +* Improve suggestion applicability for [`while_let_loop`] [#3975](https://github.com/rust-lang/rust-clippy/pull/3975)
 +* Improve diagnostics for [`too_many_arguments`] [#4053](https://github.com/rust-lang/rust-clippy/pull/4053)
 +* Improve diagnostics for [`cast_lossless`] [#4021](https://github.com/rust-lang/rust-clippy/pull/4021)
 +* Deal with macro checks in desugarings better [#4082](https://github.com/rust-lang/rust-clippy/pull/4082)
 +* Add macro check for [`unnecessary_cast`]  [#4026](https://github.com/rust-lang/rust-clippy/pull/4026)
 +* Remove [`approx_constant`]'s documentation's "Known problems" section. [#4027](https://github.com/rust-lang/rust-clippy/pull/4027)
 +* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 +* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 +
 +
 +## Rust 1.35
 +
 +Released 2019-05-20
 +
 +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
 +
 +* New lint: `drop_bounds` to detect `T: Drop` bounds
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
 +* Move [`get_unwrap`] to the restriction category
 +* Improve suggestions for [`iter_cloned_collect`]
 +* Improve suggestions for [`cast_lossless`] to suggest suffixed literals
 +* Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
 +* Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
 +* Fix false positive in [`bool_comparison`] pertaining to non-bool types
 +* Fix false positive in [`redundant_closure`] pertaining to differences in borrows
 +* Fix false positive in `option_map_unwrap_or` on non-copy types
 +* Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
 +* Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
 +* Fix false positive in [`needless_continue`] pertaining to loop labels
 +* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 +* Fix false positive for [`use_self`] in nested functions
 +* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
 +* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 +* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 +* Avoid triggering [`redundant_closure`] in macros
 +* ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
 +
 +## Rust 1.34
 +
 +Released 2019-04-10
 +
 +[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
 +
 +* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
 +* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
 +* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
 +* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
 +  configured using the `too-many-lines-threshold` configuration.
 +* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
 +* Expand `redundant_closure` to also work for methods (not only functions)
 +* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
 +* Fix false positive in `cast_sign_loss`
 +* Fix false positive in `integer_arithmetic`
 +* Fix false positive in `unit_arg`
 +* Fix false positives in `implicit_return`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `cast_lossless`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `needless_bool`
 +* Fix incorrect suggestion for `needless_range_loop`
 +* Fix incorrect suggestion for `use_self`
 +* Fix incorrect suggestion for `while_let_on_iterator`
 +* Clippy is now slightly easier to invoke in non-cargo contexts. See
 +  [#3665][pull3665] for more details.
 +* We now have [improved documentation][adding_lints] on how to add new lints
 +
 +## Rust 1.33
 +
 +Released 2019-02-26
 +
 +[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
 +
 +* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
 +* The `rust-clippy` repository is now part of the `rust-lang` org.
 +* Rename `stutter` to `module_name_repetitions`
 +* Merge `new_without_default_derive` into `new_without_default` lint
 +* Move `large_digit_groups` from `style` group to `pedantic`
 +* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
 +  comparisons against booleans
 +* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
 +* Expand `redundant_clone` to work on struct fields
 +* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
 +* Expand `use_self` to work on tuple structs and also in local macros
 +* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
 +* Fix false positives in `implicit_return`
 +* Fix false positives in `use_self`
 +* Fix false negative in `clone_on_copy`
 +* Fix false positive in `doc_markdown`
 +* Fix false positive in `empty_loop`
 +* Fix false positive in `if_same_then_else`
 +* Fix false positive in `infinite_iter`
 +* Fix false positive in `question_mark`
 +* Fix false positive in `useless_asref`
 +* Fix false positive in `wildcard_dependencies`
 +* Fix false positive in `write_with_newline`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `get_unwrap`
 +
 +## Rust 1.32
 +
 +Released 2019-01-17
 +
 +[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 +
 +* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`],
 +  [`redundant_clone`], [`wildcard_dependencies`],
 +  [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`],
 +  [`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
 +[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
 +
 +<!-- lint disable no-unused-definitions -->
 +<!-- begin autogenerated links to lint list -->
 +[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 +[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 +[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 +[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 +[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 +[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
 +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
 +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 +[`await_holding_refcell_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_refcell_ref
 +[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 +[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 +[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
 +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 +[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 +[`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 +[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 +[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 +[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 +[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
 +[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 +[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 +[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 +[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
 +[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
 +[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 +[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 +[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 +[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
 +[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 +[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 +[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 +[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 +[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
 +[`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions
 +[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
 +[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
 +[`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
 +[`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied
 +[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 +[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 +[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
 +[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 +[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 +[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 +[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 +[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 +[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 +[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 +[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 +[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
 +[`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 +[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
 +[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 +[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 +[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 +[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
 +[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 +[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 +[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 +[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 +[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 +[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 +[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 +[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 +[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 +[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 +[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 +[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 +[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
 +[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
 +[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
 +[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
 +[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
 +[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
 +[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
++[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 +[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 +[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 +[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
 +[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
 +[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
 +[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
 +[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
 +[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used
 +[`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
 +[`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop
 +[`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods
 +[`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
 +[`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
 +[`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write
 +[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 +[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
 +[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
 +[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 +[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 +[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 +[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 +[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 +[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
 +[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
 +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
 +[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
 +[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
 +[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
 +[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 +[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 +[`fn_to_numeric_cast_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
 +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 +[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 +[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 +[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 +[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 +[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 +[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
 +[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 +[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 +[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
 +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 +[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 +[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
 +[`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_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
 +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 +[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 +[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 +[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
 +[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 +[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 +[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 +[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 +[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
 +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
 +[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
 +[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
 +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 +[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
 +[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 +[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 +[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
 +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
 +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
 +[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 +[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 +[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 +[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 +[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
 +[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 +[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 +[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 +[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 +[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 +[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 +[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 +[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 +[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
 +[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 +[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 +[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
 +[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 +[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 +[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 +[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 +[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 +[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
 +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
 +[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
 +[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
 +[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
 +[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
 +[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
 +[`match_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_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
 +[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
 +[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 +[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 +[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 +[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
 +[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
 +[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 +[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
 +[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 +[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 +[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
 +[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
 +[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
 +[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
 +[`mut_mutex_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mutex_lock
 +[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
 +[`mutable_key_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
 +[`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
 +[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 +[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 +[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 +[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 +[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 +[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 +[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 +[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 +[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 +[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 +[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 +[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 +[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 +[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 +[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
 +[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
 +[`negative_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#negative_feature_names
 +[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 +[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 +[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
++[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
 +[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
 +[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 +[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 +[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
 +[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
 +[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 +[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 +[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
 +[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
 +[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 +[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 +[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 +[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 +[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 +[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 +[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 +[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
 +[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
 +[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 +[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 +[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 +[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 +[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 +[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 +[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
 +[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 +[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 +[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 +[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
 +[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
 +[`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 +[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 +[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
 +[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 +[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
 +[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 +[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 +[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 +[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 +[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 +[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 +[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 +[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 +[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 +[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 +[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 +[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 +[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 +[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 +[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
 +[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 +[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 +[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
 +[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 +[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 +[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 +[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
 +[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 +[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 +[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 +[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 +[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 +[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 +[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 +[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 +[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 +[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 +[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 +[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
 +[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 +[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 +[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
 +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 +[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 +[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
 +[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
 +[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 +[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 +[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 +[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 +[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 +[`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
 +[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 +[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 +[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
 +[`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
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 +[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 +[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 +[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
 +[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
 +[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
 +[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
 +[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
 +[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
 +[`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize
 +[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
 +[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization
 +[`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
 +[`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 +[`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 +[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
 +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 +[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 +[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 +[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 +[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 +[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
 +[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 +[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
 +[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
 +[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
 +[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
 +[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 +[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
 +[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 +[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 +[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
 +[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 +[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 +[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
 +[`vec_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
 +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 +[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 +[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 +[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 +[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 +[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 +[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
 +[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
 +[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
 +[`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports
 +[`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns
 +[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
 +[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
 +[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string
 +[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
 +[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
 +[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
 +[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 +[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 +[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
 +[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index e05db7af58677cd0f30c84fabf39fd7c40780df0,0000000000000000000000000000000000000000..5538f62c8e786c0f2f16092fa5a754ace47c5988
mode 100644,000000..100644
--- /dev/null
@@@ -1,559 -1,0 +1,38 @@@
- use itertools::Itertools;
- use regex::Regex;
- use std::collections::HashMap;
- use std::ffi::OsStr;
- use std::fs;
- use std::lazy::SyncLazy;
- use std::path::{Path, PathBuf};
- use walkdir::WalkDir;
 +#![feature(once_cell)]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +
- static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
-     Regex::new(
-         r#"(?x)
-     declare_clippy_lint!\s*[\{(]
-     (?:\s+///.*)*
-     \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-     (?P<cat>[a-z_]+)\s*,\s*
-     "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
- "#,
-     )
-     .unwrap()
- });
- static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
-     Regex::new(
-         r#"(?x)
-     declare_deprecated_lint!\s*[{(]\s*
-     (?:\s+///.*)*
-     \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-     "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
- "#,
-     )
-     .unwrap()
- });
- static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
- pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
- /// Lint data parsed from the Clippy source code.
- #[derive(Clone, PartialEq, Debug)]
- pub struct Lint {
-     pub name: String,
-     pub group: String,
-     pub desc: String,
-     pub deprecation: Option<String>,
-     pub module: String,
- }
- impl Lint {
-     #[must_use]
-     pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
-         Self {
-             name: name.to_lowercase(),
-             group: group.to_string(),
-             desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
-             deprecation: deprecation.map(ToString::to_string),
-             module: module.to_string(),
-         }
-     }
-     /// Returns all non-deprecated lints and non-internal lints
-     #[must_use]
-     pub fn usable_lints(lints: &[Self]) -> Vec<Self> {
-         lints
-             .iter()
-             .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal"))
-             .cloned()
-             .collect()
-     }
-     /// Returns all internal lints (not `internal_warn` lints)
-     #[must_use]
-     pub fn internal_lints(lints: &[Self]) -> Vec<Self> {
-         lints.iter().filter(|l| l.group == "internal").cloned().collect()
-     }
-     /// Returns all deprecated lints
-     #[must_use]
-     pub fn deprecated_lints(lints: &[Self]) -> Vec<Self> {
-         lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect()
-     }
-     /// Returns the lints in a `HashMap`, grouped by the different lint groups
-     #[must_use]
-     pub fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
-         lints.map(|lint| (lint.group.to_string(), lint)).into_group_map()
-     }
- }
- /// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
- #[must_use]
- pub fn gen_lint_group_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
-     lints
-         .map(|l| format!("        LintId::of({}::{}),", l.module, l.name.to_uppercase()))
-         .sorted()
-         .collect::<Vec<String>>()
- }
- /// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
- #[must_use]
- pub fn gen_modules_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
-     lints
-         .map(|l| &l.module)
-         .unique()
-         .map(|module| format!("mod {};", module))
-         .sorted()
-         .collect::<Vec<String>>()
- }
- /// Generates the list of lint links at the bottom of the README
- #[must_use]
- pub fn gen_changelog_lint_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
-     lints
-         .sorted_by_key(|l| &l.name)
-         .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name))
-         .collect()
- }
- /// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
- #[must_use]
- pub fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
-     lints
-         .flat_map(|l| {
-             l.deprecation
-                 .clone()
-                 .map(|depr_text| {
-                     vec![
-                         "    store.register_removed(".to_string(),
-                         format!("        \"clippy::{}\",", l.name),
-                         format!("        \"{}\",", depr_text),
-                         "    );".to_string(),
-                     ]
-                 })
-                 .expect("only deprecated lints should be passed")
-         })
-         .collect::<Vec<String>>()
- }
- #[must_use]
- pub fn gen_register_lint_list<'a>(
-     internal_lints: impl Iterator<Item = &'a Lint>,
-     usable_lints: impl Iterator<Item = &'a Lint>,
- ) -> Vec<String> {
-     let header = "    store.register_lints(&[".to_string();
-     let footer = "    ]);".to_string();
-     let internal_lints = internal_lints
-         .sorted_by_key(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
-         .map(|l| {
-             format!(
-                 "        #[cfg(feature = \"internal-lints\")]\n        {}::{},",
-                 l.module,
-                 l.name.to_uppercase()
-             )
-         });
-     let other_lints = usable_lints
-         .sorted_by_key(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
-         .map(|l| format!("        {}::{},", l.module, l.name.to_uppercase()))
-         .sorted();
-     let mut lint_list = vec![header];
-     lint_list.extend(internal_lints);
-     lint_list.extend(other_lints);
-     lint_list.push(footer);
-     lint_list
- }
- /// Gathers all files in `src/clippy_lints` and gathers all lints inside
- pub fn gather_all() -> impl Iterator<Item = Lint> {
-     lint_files().flat_map(|f| gather_from_file(&f))
- }
- fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item = Lint> {
-     let content = fs::read_to_string(dir_entry.path()).unwrap();
-     let path = dir_entry.path();
-     let filename = path.file_stem().unwrap();
-     let path_buf = path.with_file_name(filename);
-     let mut rel_path = path_buf
-         .strip_prefix(clippy_project_root().join("clippy_lints/src"))
-         .expect("only files in `clippy_lints/src` should be looked at");
-     // If the lints are stored in mod.rs, we get the module name from
-     // the containing directory:
-     if filename == "mod" {
-         rel_path = rel_path.parent().unwrap();
-     }
-     let module = rel_path
-         .components()
-         .map(|c| c.as_os_str().to_str().unwrap())
-         .collect::<Vec<_>>()
-         .join("::");
-     parse_contents(&content, &module)
- }
- fn parse_contents(content: &str, module: &str) -> impl Iterator<Item = Lint> {
-     let lints = DEC_CLIPPY_LINT_RE
-         .captures_iter(content)
-         .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module));
-     let deprecated = DEC_DEPRECATED_LINT_RE
-         .captures_iter(content)
-         .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module));
-     // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
-     lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
- }
- /// Collects all .rs files in the `clippy_lints/src` directory
- fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> {
-     // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
-     // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
-     let path = clippy_project_root().join("clippy_lints/src");
-     WalkDir::new(path)
-         .into_iter()
-         .filter_map(Result::ok)
-         .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
- }
- /// Whether a file has had its text changed or not
- #[derive(PartialEq, Debug)]
- pub struct FileChange {
-     pub changed: bool,
-     pub new_lines: String,
- }
- /// Replaces a region in a file delimited by two lines matching regexes.
- ///
- /// `path` is the relative path to the file on which you want to perform the replacement.
- ///
- /// See `replace_region_in_text` for documentation of the other options.
- ///
- /// # Panics
- ///
- /// Panics if the path could not read or then written
- pub fn replace_region_in_file<F>(
-     path: &Path,
-     start: &str,
-     end: &str,
-     replace_start: bool,
-     write_back: bool,
-     replacements: F,
- ) -> FileChange
- where
-     F: FnOnce() -> Vec<String>,
- {
-     let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e));
-     let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
-     if write_back {
-         if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) {
-             panic!("Cannot write to {}: {}", path.display(), e);
-         }
-     }
-     file_change
- }
- /// Replaces a region in a text delimited by two lines matching regexes.
- ///
- /// * `text` is the input text on which you want to perform the replacement
- /// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
- ///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
- /// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
- ///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
- /// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end`
- ///   delimiter line is never replaced.
- /// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
- ///
- /// If you want to perform the replacement on files instead of already parsed text,
- /// use `replace_region_in_file`.
- ///
- /// # Example
- ///
- /// ```
- /// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
- /// let result =
- ///     clippy_dev::replace_region_in_text(the_text, "replace_start", "replace_end", false, || {
- ///         vec!["a different".to_string(), "text".to_string()]
- ///     })
- ///     .new_lines;
- /// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
- /// ```
- ///
- /// # Panics
- ///
- /// Panics if start or end is not valid regex
- pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange
- where
-     F: FnOnce() -> Vec<String>,
- {
-     let replace_it = replacements();
-     let mut in_old_region = false;
-     let mut found = false;
-     let mut new_lines = vec![];
-     let start = Regex::new(start).unwrap();
-     let end = Regex::new(end).unwrap();
-     for line in text.lines() {
-         if in_old_region {
-             if end.is_match(line) {
-                 in_old_region = false;
-                 new_lines.extend(replace_it.clone());
-                 new_lines.push(line.to_string());
-             }
-         } else if start.is_match(line) {
-             if !replace_start {
-                 new_lines.push(line.to_string());
-             }
-             in_old_region = true;
-             found = true;
-         } else {
-             new_lines.push(line.to_string());
-         }
-     }
-     if !found {
-         // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the
-         // given text or file. Most likely this is an error on the programmer's side and the Regex
-         // is incorrect.
-         eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start);
-         std::process::exit(1);
-     }
-     let mut new_lines = new_lines.join("\n");
-     if text.ends_with('\n') {
-         new_lines.push('\n');
-     }
-     let changed = new_lines != text;
-     FileChange { changed, new_lines }
- }
++use std::path::PathBuf;
 +
 +pub mod bless;
 +pub mod fmt;
 +pub mod new_lint;
 +pub mod serve;
 +pub mod setup;
 +pub mod update_lints;
 +
- #[test]
- fn test_parse_contents() {
-     let result: Vec<Lint> = parse_contents(
-         r#"
- declare_clippy_lint! {
-     pub PTR_ARG,
-     style,
-     "really long \
-      text"
- }
- declare_clippy_lint!{
-     pub DOC_MARKDOWN,
-     pedantic,
-     "single line"
- }
- /// some doc comment
- declare_deprecated_lint! {
-     pub SHOULD_ASSERT_EQ,
-     "`assert!()` will be more flexible with RFC 2011"
- }
-     "#,
-         "module_name",
-     )
-     .collect();
-     let expected = vec![
-         Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
-         Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
-         Lint::new(
-             "should_assert_eq",
-             "Deprecated",
-             "`assert!()` will be more flexible with RFC 2011",
-             Some("`assert!()` will be more flexible with RFC 2011"),
-             "module_name",
-         ),
-     ];
-     assert_eq!(expected, result);
- }
- #[test]
- fn test_replace_region() {
-     let text = "\nabc\n123\n789\ndef\nghi";
-     let expected = FileChange {
-         changed: true,
-         new_lines: "\nabc\nhello world\ndef\nghi".to_string(),
-     };
-     let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
-         vec!["hello world".to_string()]
-     });
-     assert_eq!(expected, result);
- }
- #[test]
- fn test_replace_region_with_start() {
-     let text = "\nabc\n123\n789\ndef\nghi";
-     let expected = FileChange {
-         changed: true,
-         new_lines: "\nhello world\ndef\nghi".to_string(),
-     };
-     let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
-         vec!["hello world".to_string()]
-     });
-     assert_eq!(expected, result);
- }
- #[test]
- fn test_replace_region_no_changes() {
-     let text = "123\n456\n789";
-     let expected = FileChange {
-         changed: false,
-         new_lines: "123\n456\n789".to_string(),
-     };
-     let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new);
-     assert_eq!(expected, result);
- }
- #[test]
- fn test_usable_lints() {
-     let lints = vec![
-         Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
-         Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"),
-         Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"),
-         Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"),
-     ];
-     let expected = vec![Lint::new(
-         "should_assert_eq2",
-         "Not Deprecated",
-         "abc",
-         None,
-         "module_name",
-     )];
-     assert_eq!(expected, Lint::usable_lints(&lints));
- }
- #[test]
- fn test_by_lint_group() {
-     let lints = vec![
-         Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
-         Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
-         Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
-     ];
-     let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
-     expected.insert(
-         "group1".to_string(),
-         vec![
-             Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
-             Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
-         ],
-     );
-     expected.insert(
-         "group2".to_string(),
-         vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
-     );
-     assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
- }
- #[test]
- fn test_gen_changelog_lint_list() {
-     let lints = vec![
-         Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
-         Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
-     ];
-     let expected = vec![
-         format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
-         format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
-     ];
-     assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
- }
- #[test]
- fn test_gen_deprecated() {
-     let lints = vec![
-         Lint::new(
-             "should_assert_eq",
-             "group1",
-             "abc",
-             Some("has been superseded by should_assert_eq2"),
-             "module_name",
-         ),
-         Lint::new(
-             "another_deprecated",
-             "group2",
-             "abc",
-             Some("will be removed"),
-             "module_name",
-         ),
-     ];
-     let expected: Vec<String> = vec![
-         "    store.register_removed(",
-         "        \"clippy::should_assert_eq\",",
-         "        \"has been superseded by should_assert_eq2\",",
-         "    );",
-         "    store.register_removed(",
-         "        \"clippy::another_deprecated\",",
-         "        \"will be removed\",",
-         "    );",
-     ]
-     .into_iter()
-     .map(String::from)
-     .collect();
-     assert_eq!(expected, gen_deprecated(lints.iter()));
- }
- #[test]
- #[should_panic]
- fn test_gen_deprecated_fail() {
-     let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")];
-     let _deprecated_lints = gen_deprecated(lints.iter());
- }
- #[test]
- fn test_gen_modules_list() {
-     let lints = vec![
-         Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
-         Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"),
-     ];
-     let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()];
-     assert_eq!(expected, gen_modules_list(lints.iter()));
- }
- #[test]
- fn test_gen_lint_group_list() {
-     let lints = vec![
-         Lint::new("abc", "group1", "abc", None, "module_name"),
-         Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
-         Lint::new("internal", "internal_style", "abc", None, "module_name"),
-     ];
-     let expected = vec![
-         "        LintId::of(module_name::ABC),".to_string(),
-         "        LintId::of(module_name::INTERNAL),".to_string(),
-         "        LintId::of(module_name::SHOULD_ASSERT_EQ),".to_string(),
-     ];
-     assert_eq!(expected, gen_lint_group_list(lints.iter()));
- }
 +/// Returns the path to the Clippy project directory
 +///
 +/// # Panics
 +///
 +/// Panics if the current directory could not be retrieved, there was an error reading any of the
 +/// Cargo.toml files or ancestor directory is the clippy root directory
 +#[must_use]
 +pub fn clippy_project_root() -> PathBuf {
 +    let current_dir = std::env::current_dir().unwrap();
 +    for path in current_dir.ancestors() {
 +        let result = std::fs::read_to_string(path.join("Cargo.toml"));
 +        if let Err(err) = &result {
 +            if err.kind() == std::io::ErrorKind::NotFound {
 +                continue;
 +            }
 +        }
 +
 +        let content = result.unwrap();
 +        if content.contains("[package]\nname = \"clippy\"") {
 +            return path.to_path_buf();
 +        }
 +    }
 +    panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
 +}
index db467c26f15466de263ddd1c5a00bac7b1f995e5,0000000000000000000000000000000000000000..10d859988f6f2d55d52ac3cf035397be337aba0d
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,705 @@@
- use crate::{
-     gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list,
-     replace_region_in_file, Lint, DOCS_LINK,
- };
++use itertools::Itertools;
++use regex::Regex;
++use std::collections::HashMap;
++use std::ffi::OsStr;
++use std::fs;
++use std::lazy::SyncLazy;
 +use std::path::Path;
++use walkdir::WalkDir;
++
++use crate::clippy_project_root;
++
++const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
++     // Use that command to update this file and do not edit by hand.\n\
++     // Manual edits will be overwritten.\n\n";
++
++static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
++    Regex::new(
++        r#"(?x)
++    declare_clippy_lint!\s*[\{(]
++    (?:\s+///.*)*
++    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
++    (?P<cat>[a-z_]+)\s*,\s*
++    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
++"#,
++    )
++    .unwrap()
++});
++
++static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
++    Regex::new(
++        r#"(?x)
++    declare_deprecated_lint!\s*[{(]\s*
++    (?:\s+///.*)*
++    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
++    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
++"#,
++    )
++    .unwrap()
++});
++static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
++
++static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
 +
 +#[derive(Clone, Copy, PartialEq)]
 +pub enum UpdateMode {
 +    Check,
 +    Change,
 +}
 +
++/// Runs the `update_lints` command.
++///
++/// This updates various generated values from the lint source code.
++///
++/// `update_mode` indicates if the files should be updated or if updates should be checked for.
++///
++/// # Panics
++///
++/// Panics if a file path could not read from or then written to
 +#[allow(clippy::too_many_lines)]
 +pub fn run(update_mode: UpdateMode) {
 +    let lint_list: Vec<Lint> = gather_all().collect();
 +
 +    let internal_lints = Lint::internal_lints(&lint_list);
 +    let deprecated_lints = Lint::deprecated_lints(&lint_list);
 +    let usable_lints = Lint::usable_lints(&lint_list);
 +    let mut sorted_usable_lints = usable_lints.clone();
 +    sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
 +
 +    let usable_lint_count = round_to_fifty(usable_lints.len());
 +
 +    let mut file_change = false;
 +
 +    file_change |= replace_region_in_file(
 +        Path::new("README.md"),
 +        &format!(
 +            r#"\[There are over \d+ lints included in this crate!\]\({}\)"#,
 +            DOCS_LINK
 +        ),
 +        "",
 +        true,
 +        update_mode == UpdateMode::Change,
 +        || {
 +            vec![format!(
 +                "[There are over {} lints included in this crate!]({})",
 +                usable_lint_count, DOCS_LINK
 +            )]
 +        },
 +    )
 +    .changed;
 +
 +    file_change |= replace_region_in_file(
 +        Path::new("CHANGELOG.md"),
 +        "<!-- begin autogenerated links to lint list -->",
 +        "<!-- end autogenerated links to lint list -->",
 +        false,
 +        update_mode == UpdateMode::Change,
 +        || gen_changelog_lint_list(usable_lints.iter().chain(deprecated_lints.iter())),
 +    )
 +    .changed;
 +
-     file_change |= replace_region_in_file(
-         Path::new("clippy_lints/src/lib.rs"),
-         "begin deprecated lints",
-         "end deprecated lints",
-         false,
-         update_mode == UpdateMode::Change,
-         || gen_deprecated(deprecated_lints.iter()),
-     )
-     .changed;
-     file_change |= replace_region_in_file(
-         Path::new("clippy_lints/src/lib.rs"),
-         "begin register lints",
-         "end register lints",
-         false,
-         update_mode == UpdateMode::Change,
-         || gen_register_lint_list(internal_lints.iter(), usable_lints.iter()),
-     )
-     .changed;
++    // This has to be in lib.rs, otherwise rustfmt doesn't work
 +    file_change |= replace_region_in_file(
 +        Path::new("clippy_lints/src/lib.rs"),
 +        "begin lints modules",
 +        "end lints modules",
 +        false,
 +        update_mode == UpdateMode::Change,
 +        || gen_modules_list(usable_lints.iter()),
 +    )
 +    .changed;
 +
-     // Generate lists of lints in the clippy::all lint group
-     file_change |= replace_region_in_file(
-         Path::new("clippy_lints/src/lib.rs"),
-         r#"store.register_group\(true, "clippy::all""#,
-         r#"\]\);"#,
-         false,
-         update_mode == UpdateMode::Change,
-         || {
-             // clippy::all should only include the following lint groups:
-             let all_group_lints = usable_lints.iter().filter(|l| {
-                 matches!(
-                     &*l.group,
-                     "correctness" | "suspicious" | "style" | "complexity" | "perf"
-                 )
-             });
-             gen_lint_group_list(all_group_lints)
-         },
-     )
-     .changed;
++    if file_change && update_mode == UpdateMode::Check {
++        exit_with_failure();
++    }
 +
-     // Generate the list of lints for all other lint groups
-     for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
-         file_change |= replace_region_in_file(
-             Path::new("clippy_lints/src/lib.rs"),
-             &format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
-             r#"\]\);"#,
-             false,
-             update_mode == UpdateMode::Change,
-             || gen_lint_group_list(lints.iter()),
++    process_file(
++        "clippy_lints/src/lib.register_lints.rs",
++        update_mode,
++        &gen_register_lint_list(internal_lints.iter(), usable_lints.iter()),
++    );
++    process_file(
++        "clippy_lints/src/lib.deprecated.rs",
++        update_mode,
++        &gen_deprecated(deprecated_lints.iter()),
++    );
++
++    let all_group_lints = usable_lints.iter().filter(|l| {
++        matches!(
++            &*l.group,
++            "correctness" | "suspicious" | "style" | "complexity" | "perf"
 +        )
-         .changed;
-     }
++    });
++    let content = gen_lint_group_list("all", all_group_lints);
++    process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
 +
-     if update_mode == UpdateMode::Check && file_change {
-         println!(
-             "Not all lints defined properly. \
-              Please run `cargo dev update_lints` to make sure all lints are defined properly."
++    for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
++        let content = gen_lint_group_list(&lint_group, lints.iter());
++        process_file(
++            &format!("clippy_lints/src/lib.register_{}.rs", lint_group),
++            update_mode,
++            &content,
 +        );
-         std::process::exit(1);
 +    }
 +}
 +
 +pub fn print_lints() {
 +    let lint_list: Vec<Lint> = gather_all().collect();
 +    let usable_lints = Lint::usable_lints(&lint_list);
 +    let usable_lint_count = usable_lints.len();
 +    let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
 +
 +    for (lint_group, mut lints) in grouped_by_lint_group {
 +        if lint_group == "Deprecated" {
 +            continue;
 +        }
 +        println!("\n## {}", lint_group);
 +
 +        lints.sort_by_key(|l| l.name.clone());
 +
 +        for lint in lints {
 +            println!("* [{}]({}#{}) ({})", lint.name, DOCS_LINK, lint.name, lint.desc);
 +        }
 +    }
 +
 +    println!("there are {} lints", usable_lint_count);
 +}
 +
 +fn round_to_fifty(count: usize) -> usize {
 +    count / 50 * 50
 +}
++
++fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str) {
++    if update_mode == UpdateMode::Check {
++        let old_content =
++            fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e));
++        if content != old_content {
++            exit_with_failure();
++        }
++    } else {
++        fs::write(&path, content.as_bytes())
++            .unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e));
++    }
++}
++
++fn exit_with_failure() {
++    println!(
++        "Not all lints defined properly. \
++                 Please run `cargo dev update_lints` to make sure all lints are defined properly."
++    );
++    std::process::exit(1);
++}
++
++/// Lint data parsed from the Clippy source code.
++#[derive(Clone, PartialEq, Debug)]
++struct Lint {
++    name: String,
++    group: String,
++    desc: String,
++    deprecation: Option<String>,
++    module: String,
++}
++
++impl Lint {
++    #[must_use]
++    fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
++        Self {
++            name: name.to_lowercase(),
++            group: group.to_string(),
++            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
++            deprecation: deprecation.map(ToString::to_string),
++            module: module.to_string(),
++        }
++    }
++
++    /// Returns all non-deprecated lints and non-internal lints
++    #[must_use]
++    fn usable_lints(lints: &[Self]) -> Vec<Self> {
++        lints
++            .iter()
++            .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal"))
++            .cloned()
++            .collect()
++    }
++
++    /// Returns all internal lints (not `internal_warn` lints)
++    #[must_use]
++    fn internal_lints(lints: &[Self]) -> Vec<Self> {
++        lints.iter().filter(|l| l.group == "internal").cloned().collect()
++    }
++
++    /// Returns all deprecated lints
++    #[must_use]
++    fn deprecated_lints(lints: &[Self]) -> Vec<Self> {
++        lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect()
++    }
++
++    /// Returns the lints in a `HashMap`, grouped by the different lint groups
++    #[must_use]
++    fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
++        lints.map(|lint| (lint.group.to_string(), lint)).into_group_map()
++    }
++}
++
++/// Generates the code for registering a group
++fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator<Item = &'a Lint>) -> String {
++    let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect();
++    details.sort_unstable();
++
++    let mut output = GENERATED_FILE_COMMENT.to_string();
++
++    output.push_str(&format!(
++        "store.register_group(true, \"clippy::{0}\", Some(\"clippy_{0}\"), vec![\n",
++        group_name
++    ));
++    for (module, name) in details {
++        output.push_str(&format!("    LintId::of({}::{}),\n", module, name));
++    }
++    output.push_str("])\n");
++
++    output
++}
++
++/// Generates the module declarations for `lints`
++#[must_use]
++fn gen_modules_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
++    lints
++        .map(|l| &l.module)
++        .unique()
++        .map(|module| format!("mod {};", module))
++        .sorted()
++        .collect::<Vec<String>>()
++}
++
++/// Generates the list of lint links at the bottom of the CHANGELOG
++#[must_use]
++fn gen_changelog_lint_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
++    lints
++        .sorted_by_key(|l| &l.name)
++        .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name))
++        .collect()
++}
++
++/// Generates the `register_removed` code
++#[must_use]
++fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> String {
++    let mut output = GENERATED_FILE_COMMENT.to_string();
++    output.push_str("{\n");
++    for Lint { name, deprecation, .. } in lints {
++        output.push_str(&format!(
++            concat!(
++                "    store.register_removed(\n",
++                "        \"clippy::{}\",\n",
++                "        \"{}\",\n",
++                "    );\n"
++            ),
++            name,
++            deprecation.as_ref().expect("`lints` are deprecated")
++        ));
++    }
++    output.push_str("}\n");
++
++    output
++}
++
++/// Generates the code for registering lints
++#[must_use]
++fn gen_register_lint_list<'a>(
++    internal_lints: impl Iterator<Item = &'a Lint>,
++    usable_lints: impl Iterator<Item = &'a Lint>,
++) -> String {
++    let mut details: Vec<_> = internal_lints
++        .map(|l| (false, &l.module, l.name.to_uppercase()))
++        .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase())))
++        .collect();
++    details.sort_unstable();
++
++    let mut output = GENERATED_FILE_COMMENT.to_string();
++    output.push_str("store.register_lints(&[\n");
++
++    for (is_public, module_name, lint_name) in details {
++        if !is_public {
++            output.push_str("    #[cfg(feature = \"internal-lints\")]\n");
++        }
++        output.push_str(&format!("    {}::{},\n", module_name, lint_name));
++    }
++    output.push_str("])\n");
++
++    output
++}
++
++/// Gathers all files in `src/clippy_lints` and gathers all lints inside
++fn gather_all() -> impl Iterator<Item = Lint> {
++    lint_files().flat_map(|f| gather_from_file(&f))
++}
++
++fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item = Lint> {
++    let content = fs::read_to_string(dir_entry.path()).unwrap();
++    let path = dir_entry.path();
++    let filename = path.file_stem().unwrap();
++    let path_buf = path.with_file_name(filename);
++    let mut rel_path = path_buf
++        .strip_prefix(clippy_project_root().join("clippy_lints/src"))
++        .expect("only files in `clippy_lints/src` should be looked at");
++    // If the lints are stored in mod.rs, we get the module name from
++    // the containing directory:
++    if filename == "mod" {
++        rel_path = rel_path.parent().unwrap();
++    }
++
++    let module = rel_path
++        .components()
++        .map(|c| c.as_os_str().to_str().unwrap())
++        .collect::<Vec<_>>()
++        .join("::");
++
++    parse_contents(&content, &module)
++}
++
++fn parse_contents(content: &str, module: &str) -> impl Iterator<Item = Lint> {
++    let lints = DEC_CLIPPY_LINT_RE
++        .captures_iter(content)
++        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module));
++    let deprecated = DEC_DEPRECATED_LINT_RE
++        .captures_iter(content)
++        .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module));
++    // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
++    lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
++}
++
++/// Collects all .rs files in the `clippy_lints/src` directory
++fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> {
++    // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
++    // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
++    let path = clippy_project_root().join("clippy_lints/src");
++    WalkDir::new(path)
++        .into_iter()
++        .filter_map(Result::ok)
++        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
++}
++
++/// Whether a file has had its text changed or not
++#[derive(PartialEq, Debug)]
++struct FileChange {
++    changed: bool,
++    new_lines: String,
++}
++
++/// Replaces a region in a file delimited by two lines matching regexes.
++///
++/// `path` is the relative path to the file on which you want to perform the replacement.
++///
++/// See `replace_region_in_text` for documentation of the other options.
++///
++/// # Panics
++///
++/// Panics if the path could not read or then written
++fn replace_region_in_file<F>(
++    path: &Path,
++    start: &str,
++    end: &str,
++    replace_start: bool,
++    write_back: bool,
++    replacements: F,
++) -> FileChange
++where
++    F: FnOnce() -> Vec<String>,
++{
++    let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e));
++    let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
++
++    if write_back {
++        if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) {
++            panic!("Cannot write to {}: {}", path.display(), e);
++        }
++    }
++    file_change
++}
++
++/// Replaces a region in a text delimited by two lines matching regexes.
++///
++/// * `text` is the input text on which you want to perform the replacement
++/// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
++///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
++/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
++///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
++/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end`
++///   delimiter line is never replaced.
++/// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
++///
++/// If you want to perform the replacement on files instead of already parsed text,
++/// use `replace_region_in_file`.
++///
++/// # Example
++///
++/// ```ignore
++/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
++/// let result =
++///     replace_region_in_text(the_text, "replace_start", "replace_end", false, || {
++///         vec!["a different".to_string(), "text".to_string()]
++///     })
++///     .new_lines;
++/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
++/// ```
++///
++/// # Panics
++///
++/// Panics if start or end is not valid regex
++fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange
++where
++    F: FnOnce() -> Vec<String>,
++{
++    let replace_it = replacements();
++    let mut in_old_region = false;
++    let mut found = false;
++    let mut new_lines = vec![];
++    let start = Regex::new(start).unwrap();
++    let end = Regex::new(end).unwrap();
++
++    for line in text.lines() {
++        if in_old_region {
++            if end.is_match(line) {
++                in_old_region = false;
++                new_lines.extend(replace_it.clone());
++                new_lines.push(line.to_string());
++            }
++        } else if start.is_match(line) {
++            if !replace_start {
++                new_lines.push(line.to_string());
++            }
++            in_old_region = true;
++            found = true;
++        } else {
++            new_lines.push(line.to_string());
++        }
++    }
++
++    if !found {
++        // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the
++        // given text or file. Most likely this is an error on the programmer's side and the Regex
++        // is incorrect.
++        eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start);
++        std::process::exit(1);
++    }
++
++    let mut new_lines = new_lines.join("\n");
++    if text.ends_with('\n') {
++        new_lines.push('\n');
++    }
++    let changed = new_lines != text;
++    FileChange { changed, new_lines }
++}
++
++#[test]
++fn test_parse_contents() {
++    let result: Vec<Lint> = parse_contents(
++        r#"
++declare_clippy_lint! {
++    pub PTR_ARG,
++    style,
++    "really long \
++     text"
++}
++
++declare_clippy_lint!{
++    pub DOC_MARKDOWN,
++    pedantic,
++    "single line"
++}
++
++/// some doc comment
++declare_deprecated_lint! {
++    pub SHOULD_ASSERT_EQ,
++    "`assert!()` will be more flexible with RFC 2011"
++}
++    "#,
++        "module_name",
++    )
++    .collect();
++
++    let expected = vec![
++        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
++        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
++        Lint::new(
++            "should_assert_eq",
++            "Deprecated",
++            "`assert!()` will be more flexible with RFC 2011",
++            Some("`assert!()` will be more flexible with RFC 2011"),
++            "module_name",
++        ),
++    ];
++    assert_eq!(expected, result);
++}
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++
++    #[test]
++    fn test_replace_region() {
++        let text = "\nabc\n123\n789\ndef\nghi";
++        let expected = FileChange {
++            changed: true,
++            new_lines: "\nabc\nhello world\ndef\nghi".to_string(),
++        };
++        let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
++            vec!["hello world".to_string()]
++        });
++        assert_eq!(expected, result);
++    }
++
++    #[test]
++    fn test_replace_region_with_start() {
++        let text = "\nabc\n123\n789\ndef\nghi";
++        let expected = FileChange {
++            changed: true,
++            new_lines: "\nhello world\ndef\nghi".to_string(),
++        };
++        let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
++            vec!["hello world".to_string()]
++        });
++        assert_eq!(expected, result);
++    }
++
++    #[test]
++    fn test_replace_region_no_changes() {
++        let text = "123\n456\n789";
++        let expected = FileChange {
++            changed: false,
++            new_lines: "123\n456\n789".to_string(),
++        };
++        let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new);
++        assert_eq!(expected, result);
++    }
++
++    #[test]
++    fn test_usable_lints() {
++        let lints = vec![
++            Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
++            Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"),
++            Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"),
++            Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"),
++        ];
++        let expected = vec![Lint::new(
++            "should_assert_eq2",
++            "Not Deprecated",
++            "abc",
++            None,
++            "module_name",
++        )];
++        assert_eq!(expected, Lint::usable_lints(&lints));
++    }
++
++    #[test]
++    fn test_by_lint_group() {
++        let lints = vec![
++            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
++            Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
++            Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
++        ];
++        let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
++        expected.insert(
++            "group1".to_string(),
++            vec![
++                Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
++                Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
++            ],
++        );
++        expected.insert(
++            "group2".to_string(),
++            vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
++        );
++        assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
++    }
++
++    #[test]
++    fn test_gen_changelog_lint_list() {
++        let lints = vec![
++            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
++            Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
++        ];
++        let expected = vec![
++            format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
++            format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
++        ];
++        assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
++    }
++
++    #[test]
++    fn test_gen_deprecated() {
++        let lints = vec![
++            Lint::new(
++                "should_assert_eq",
++                "group1",
++                "abc",
++                Some("has been superseded by should_assert_eq2"),
++                "module_name",
++            ),
++            Lint::new(
++                "another_deprecated",
++                "group2",
++                "abc",
++                Some("will be removed"),
++                "module_name",
++            ),
++        ];
++
++        let expected = GENERATED_FILE_COMMENT.to_string()
++            + &[
++                "{",
++                "    store.register_removed(",
++                "        \"clippy::should_assert_eq\",",
++                "        \"has been superseded by should_assert_eq2\",",
++                "    );",
++                "    store.register_removed(",
++                "        \"clippy::another_deprecated\",",
++                "        \"will be removed\",",
++                "    );",
++                "}",
++            ]
++            .join("\n")
++            + "\n";
++
++        assert_eq!(expected, gen_deprecated(lints.iter()));
++    }
++
++    #[test]
++    #[should_panic]
++    fn test_gen_deprecated_fail() {
++        let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")];
++        let _deprecated_lints = gen_deprecated(lints.iter());
++    }
++
++    #[test]
++    fn test_gen_modules_list() {
++        let lints = vec![
++            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
++            Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"),
++        ];
++        let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()];
++        assert_eq!(expected, gen_modules_list(lints.iter()));
++    }
++
++    #[test]
++    fn test_gen_lint_group_list() {
++        let lints = vec![
++            Lint::new("abc", "group1", "abc", None, "module_name"),
++            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
++            Lint::new("internal", "internal_style", "abc", None, "module_name"),
++        ];
++        let expected = GENERATED_FILE_COMMENT.to_string()
++            + &[
++                "store.register_group(true, \"clippy::group1\", Some(\"clippy_group1\"), vec![",
++                "    LintId::of(module_name::ABC),",
++                "    LintId::of(module_name::INTERNAL),",
++                "    LintId::of(module_name::SHOULD_ASSERT_EQ),",
++                "])",
++            ]
++            .join("\n")
++            + "\n";
++
++        let result = gen_lint_group_list("group1", lints.iter());
++
++        assert_eq!(expected, result);
++    }
++}
index 2ef7dcc1775a6bfe9d6bf2d6784389c7839ff993,0000000000000000000000000000000000000000..6f8b645dd70d1f7981633f304b2139dbfc4ac15b
mode 100644,000000..100644
--- /dev/null
@@@ -1,649 -1,0 +1,649 @@@
-         if let AttrStyle::Outer = attr.style;
 +//! checks for attributes
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::match_panic_def_id;
 +use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
 +use if_chain::if_chain;
 +use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +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] = &["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)]`,
 +    /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and
 +    /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on
 +    /// `extern crate` items with a `#[macro_use]` attribute.
 +    ///
 +    /// ### Why is this bad?
 +    /// Lint attributes have no effect on crate imports. Most
 +    /// likely a `!` was forgotten.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// #[deny(dead_code)]
 +    /// extern crate foo;
 +    /// #[forbid(dead_code)]
 +    /// use foo::bar;
 +    ///
 +    /// // Ok
 +    /// #[allow(unused_imports)]
 +    /// use foo::baz;
 +    /// #[allow(unused_imports)]
 +    /// #[macro_use]
 +    /// extern crate baz;
 +    /// ```
 +    pub USELESS_ATTRIBUTE,
 +    correctness,
 +    "use of lint attributes on `extern crate` items"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `#[deprecated]` annotations with a `since`
 +    /// field that is not a valid semantic version.
 +    ///
 +    /// ### Why is this bad?
 +    /// For checking the version of the deprecation, it must be
 +    /// a valid semver. Failing that, the contained information is useless.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// #[deprecated(since = "forever")]
 +    /// fn something_else() { /* ... */ }
 +    /// ```
 +    pub DEPRECATED_SEMVER,
 +    correctness,
 +    "use of `#[deprecated(since = \"x\")]` where x is not semver"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for empty lines after outer attributes
 +    ///
 +    /// ### Why is this bad?
 +    /// Most likely the attribute was meant to be an inner attribute using a '!'.
 +    /// If it was meant to be an outer attribute, then the following item
 +    /// should not be separated by empty lines.
 +    ///
 +    /// ### Known problems
 +    /// Can cause false positives.
 +    ///
 +    /// From the clippy side it's difficult to detect empty lines between an attributes and the
 +    /// following item because empty lines and comments are not part of the AST. The parsing
 +    /// currently works for basic cases but is not perfect.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Good (as inner attribute)
 +    /// #![allow(dead_code)]
 +    ///
 +    /// fn this_is_fine() { }
 +    ///
 +    /// // Bad
 +    /// #[allow(dead_code)]
 +    ///
 +    /// fn not_quite_good_code() { }
 +    ///
 +    /// // Good (as outer attribute)
 +    /// #[allow(dead_code)]
 +    /// fn this_is_fine_too() { }
 +    /// ```
 +    pub EMPTY_LINE_AFTER_OUTER_ATTR,
 +    nursery,
 +    "empty line after outer attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
 +    ///
 +    /// ### Why is this bad?
 +    /// Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
 +    /// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #![deny(clippy::restriction)]
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #![deny(clippy::as_conversions)]
 +    /// ```
 +    pub BLANKET_CLIPPY_RESTRICTION_LINTS,
 +    suspicious,
 +    "enabling the complete restriction group"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
 +    /// with `#[rustfmt::skip]`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
 +    /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
 +    ///
 +    /// ### Known problems
 +    /// This lint doesn't detect crate level inner attributes, because they get
 +    /// processed before the PreExpansionPass lints get executed. See
 +    /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #[cfg_attr(rustfmt, rustfmt_skip)]
 +    /// fn main() { }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #[rustfmt::skip]
 +    /// fn main() { }
 +    /// ```
 +    pub DEPRECATED_CFG_ATTR,
 +    complexity,
 +    "usage of `cfg_attr(rustfmt)` instead of tool attributes"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for cfg attributes having operating systems used in target family position.
 +    ///
 +    /// ### Why is this bad?
 +    /// The configuration option will not be recognised and the related item will not be included
 +    /// by the conditional compilation engine.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// #[cfg(linux)]
 +    /// fn conditional() { }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// #[cfg(target_os = "linux")]
 +    /// fn conditional() { }
 +    /// ```
 +    ///
 +    /// Or:
 +    /// ```rust
 +    /// #[cfg(unix)]
 +    /// fn conditional() { }
 +    /// ```
 +    /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
 +    pub MISMATCHED_TARGET_OS,
 +    correctness,
 +    "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`"
 +}
 +
 +declare_lint_pass!(Attributes => [
 +    INLINE_ALWAYS,
 +    DEPRECATED_SEMVER,
 +    USELESS_ATTRIBUTE,
 +    BLANKET_CLIPPY_RESTRICTION_LINTS,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Attributes {
 +    fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
 +        if let Some(items) = &attr.meta_item_list() {
 +            if let Some(ident) = attr.ident() {
 +                if is_lint_level(ident.name) {
 +                    check_clippy_lint_names(cx, ident.name, items);
 +                }
 +                if items.is_empty() || !attr.has_name(sym::deprecated) {
 +                    return;
 +                }
 +                for item in items {
 +                    if_chain! {
 +                        if let NestedMetaItem::MetaItem(mi) = &item;
 +                        if let MetaItemKind::NameValue(lit) = &mi.kind;
 +                        if mi.has_name(sym::since);
 +                        then {
 +                            check_semver(cx, item.span(), lit);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        if is_relevant_item(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, attrs);
 +        }
 +        match item.kind {
 +            ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
 +                let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));
 +
 +                for attr in attrs {
 +                    if in_external_macro(cx.sess(), attr.span) {
 +                        return;
 +                    }
 +                    if let Some(lint_list) = &attr.meta_item_list() {
 +                        if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) {
 +                            // permit `unused_imports`, `deprecated`, `unreachable_pub`,
 +                            // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
 +                            // and `unused_imports` for `extern crate` items with `macro_use`
 +                            for lint in lint_list {
 +                                match item.kind {
 +                                    ItemKind::Use(..) => {
 +                                        if is_word(lint, sym!(unused_imports))
 +                                            || is_word(lint, sym::deprecated)
 +                                            || is_word(lint, sym!(unreachable_pub))
 +                                            || is_word(lint, sym!(unused))
 +                                            || extract_clippy_lint(lint).map_or(false, |s| s == "wildcard_imports")
 +                                            || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use")
 +                                        {
 +                                            return;
 +                                        }
 +                                    },
 +                                    ItemKind::ExternCrate(..) => {
 +                                        if is_word(lint, sym!(unused_imports)) && skip_unused_imports {
 +                                            return;
 +                                        }
 +                                        if is_word(lint, sym!(unused_extern_crates)) {
 +                                            return;
 +                                        }
 +                                    },
 +                                    _ => {},
 +                                }
 +                            }
 +                            let line_span = first_line_of_span(cx, attr.span);
 +
 +                            if let Some(mut sugg) = snippet_opt(cx, line_span) {
 +                                if sugg.contains("#[") {
 +                                    span_lint_and_then(
 +                                        cx,
 +                                        USELESS_ATTRIBUTE,
 +                                        line_span,
 +                                        "useless lint attribute",
 +                                        |diag| {
 +                                            sugg = sugg.replacen("#[", "#![", 1);
 +                                            diag.span_suggestion(
 +                                                line_span,
 +                                                "if you just forgot a `!`, use",
 +                                                sugg,
 +                                                Applicability::MaybeIncorrect,
 +                                            );
 +                                        },
 +                                    );
 +                                }
 +                            }
 +                        }
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if is_relevant_impl(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if is_relevant_trait(cx, item) {
 +            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
 +        }
 +    }
 +}
 +
 +/// Returns the lint name if it is clippy lint.
 +fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<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.name == sym::clippy;
 +        then {
 +            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
 +            return Some(lint_name.as_str());
 +        }
 +    }
 +    None
 +}
 +
 +fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) {
 +    for lint in items {
 +        if let Some(lint_name) = extract_clippy_lint(lint) {
 +            if lint_name == "restriction" && name != sym::allow {
 +                span_lint_and_help(
 +                    cx,
 +                    BLANKET_CLIPPY_RESTRICTION_LINTS,
 +                    lint.span(),
 +                    "restriction lints are not meant to be all enabled",
 +                    None,
 +                    "try enabling only the lints you really need",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 +    if let ItemKind::Fn(_, _, eid) = item.kind {
 +        is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
 +    } else {
 +        true
 +    }
 +}
 +
 +fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
 +    match item.kind {
 +        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
 +        _ => false,
 +    }
 +}
 +
 +fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
 +    match item.kind {
 +        TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
 +        TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
 +            is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool {
 +    block.stmts.first().map_or(
 +        block
 +            .expr
 +            .as_ref()
 +            .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)),
 +        |stmt| match &stmt.kind {
 +            StmtKind::Local(_) => true,
 +            StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
 +            StmtKind::Item(_) => false,
 +        },
 +    )
 +}
 +
 +fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
 +    match &expr.kind {
 +        ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
 +        ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
 +        ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
 +        ExprKind::Call(path_expr, _) => {
 +            if let ExprKind::Path(qpath) = &path_expr.kind {
 +                typeck_results
 +                    .qpath_res(qpath, path_expr.hir_id)
 +                    .opt_def_id()
 +                    .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id))
 +            } else {
 +                true
 +            }
 +        },
 +        _ => true,
 +    }
 +}
 +
 +fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
 +    if span.from_expansion() {
 +        return;
 +    }
 +
 +    for attr in attrs {
 +        if let Some(values) = attr.meta_item_list() {
 +            if values.len() != 1 || !attr.has_name(sym::inline) {
 +                continue;
 +            }
 +            if is_word(&values[0], sym::always) {
 +                span_lint(
 +                    cx,
 +                    INLINE_ALWAYS,
 +                    attr.span,
 +                    &format!(
 +                        "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
 +                        name
 +                    ),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) {
 +    if let LitKind::Str(is, _) = lit.kind {
 +        if Version::parse(&is.as_str()).is_ok() {
 +            return;
 +        }
 +    }
 +    span_lint(
 +        cx,
 +        DEPRECATED_SEMVER,
 +        span,
 +        "the since field must contain a semver-compliant version",
 +    );
 +}
 +
 +fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
 +    if let NestedMetaItem::MetaItem(mi) = &nmi {
 +        mi.is_word() && mi.has_name(expected)
 +    } else {
 +        false
 +    }
 +}
 +
 +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(), item.span.parent());
 +            let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());
 +
 +            if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
 +                let lines = snippet.split('\n').collect::<Vec<_>>();
 +                let lines = without_block_comments(lines);
 +
 +                if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
 +                    span_lint(
 +                        cx,
 +                        EMPTY_LINE_AFTER_OUTER_ATTR,
 +                        begin_of_attr_to_item,
 +                        "found an empty line after an outer attribute. \
 +                        Perhaps you forgot to add a `!` to make it an inner attribute?",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
 +    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 attr.style == AttrStyle::Outer;
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                DEPRECATED_CFG_ATTR,
 +                attr.span,
 +                "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes",
 +                "use",
 +                "#[rustfmt::skip]".to_string(),
 +                Applicability::MachineApplicable,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
 +    fn find_os(name: &str) -> Option<&'static str> {
 +        UNIX_SYSTEMS
 +            .iter()
 +            .chain(NON_UNIX_SYSTEMS.iter())
 +            .find(|&&os| os == name)
 +            .copied()
 +    }
 +
 +    fn is_unix(name: &str) -> bool {
 +        UNIX_SYSTEMS.iter().any(|&os| os == name)
 +    }
 +
 +    fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> {
 +        let mut mismatched = Vec::new();
 +
 +        for item in items {
 +            if let NestedMetaItem::MetaItem(meta) = item {
 +                match &meta.kind {
 +                    MetaItemKind::List(list) => {
 +                        mismatched.extend(find_mismatched_target_os(list));
 +                    },
 +                    MetaItemKind::Word => {
 +                        if_chain! {
 +                            if let Some(ident) = meta.ident();
 +                            if let Some(os) = find_os(&*ident.name.as_str());
 +                            then {
 +                                mismatched.push((os, ident.span));
 +                            }
 +                        }
 +                    },
 +                    MetaItemKind::NameValue(..) => {},
 +                }
 +            }
 +        }
 +
 +        mismatched
 +    }
 +
 +    if_chain! {
 +        if attr.has_name(sym::cfg);
 +        if let Some(list) = attr.meta_item_list();
 +        let mismatched = find_mismatched_target_os(&list);
 +        if !mismatched.is_empty();
 +        then {
 +            let mess = "operating system used in target family position";
 +
 +            span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
 +                // Avoid showing the unix suggestion multiple times in case
 +                // we have more than one mismatch for unix-like systems
 +                let mut unix_suggested = false;
 +
 +                for (os, span) in mismatched {
 +                    let sugg = format!("target_os = \"{}\"", os);
 +                    diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
 +
 +                    if !unix_suggested && is_unix(os) {
 +                        diag.help("did you mean `unix`?");
 +                        unix_suggested = true;
 +                    }
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +fn is_lint_level(symbol: Symbol) -> bool {
 +    matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid)
 +}
index 0cc79c8b6e8cb4449ad75f5426aa68ac6d72fd59,0000000000000000000000000000000000000000..28615b9217cd342df10851a1a308409f6c36a693
mode 100644,000000..100644
--- /dev/null
@@@ -1,153 -1,0 +1,153 @@@
-     /// There are two potential solutions. One is to use an asynx-aware Mutex
 +use clippy_utils::diagnostics::span_lint_and_note;
 +use clippy_utils::{match_def_path, paths};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::GeneratorInteriorTypeCause;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to await while holding a
 +    /// non-async-aware MutexGuard.
 +    ///
 +    /// ### Why is this bad?
 +    /// The Mutex types found in std::sync and parking_lot
 +    /// are not designed to operate in an async context across await points.
 +    ///
++    /// There are two potential solutions. One is to use an async-aware Mutex
 +    /// type. Many asynchronous foundation crates provide such a Mutex type. The
 +    /// other solution is to ensure the mutex is unlocked before calling await,
 +    /// either by introducing a scope or an explicit call to Drop::drop.
 +    ///
 +    /// ### Known problems
 +    /// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// use std::sync::Mutex;
 +    ///
 +    /// async fn foo(x: &Mutex<u32>) {
 +    ///   let guard = x.lock().unwrap();
 +    ///   *guard += 1;
 +    ///   bar.await;
 +    /// }
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// use std::sync::Mutex;
 +    ///
 +    /// async fn foo(x: &Mutex<u32>) {
 +    ///   {
 +    ///     let guard = x.lock().unwrap();
 +    ///     *guard += 1;
 +    ///   }
 +    ///   bar.await;
 +    /// }
 +    /// ```
 +    pub AWAIT_HOLDING_LOCK,
 +    pedantic,
 +    "Inside an async function, holding a MutexGuard while calling await"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to await while holding a
 +    /// `RefCell` `Ref` or `RefMut`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `RefCell` refs only check for exclusive mutable access
 +    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
 +    /// risks panics from a mutable ref shared while other refs are outstanding.
 +    ///
 +    /// ### Known problems
 +    /// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// use std::cell::RefCell;
 +    ///
 +    /// async fn foo(x: &RefCell<u32>) {
 +    ///   let mut y = x.borrow_mut();
 +    ///   *y += 1;
 +    ///   bar.await;
 +    /// }
 +    /// ```
 +    ///
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// use std::cell::RefCell;
 +    ///
 +    /// async fn foo(x: &RefCell<u32>) {
 +    ///   {
 +    ///      let mut y = x.borrow_mut();
 +    ///      *y += 1;
 +    ///   }
 +    ///   bar.await;
 +    /// }
 +    /// ```
 +    pub AWAIT_HOLDING_REFCELL_REF,
 +    pedantic,
 +    "Inside an async function, holding a RefCell ref while calling await"
 +}
 +
 +declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);
 +
 +impl LateLintPass<'_> for AwaitHolding {
 +    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
 +        use AsyncGeneratorKind::{Block, Closure, Fn};
 +        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
 +            let body_id = BodyId {
 +                hir_id: body.value.hir_id,
 +            };
 +            let typeck_results = cx.tcx.typeck_body(body_id);
 +            check_interior_types(
 +                cx,
 +                typeck_results.generator_interior_types.as_ref().skip_binder(),
 +                body.value.span,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
 +    for ty_cause in ty_causes {
 +        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
 +            if is_mutex_guard(cx, adt.did) {
 +                span_lint_and_note(
 +                    cx,
 +                    AWAIT_HOLDING_LOCK,
 +                    ty_cause.span,
 +                    "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await",
 +                    ty_cause.scope_span.or(Some(span)),
 +                    "these are all the await points this lock is held through",
 +                );
 +            }
 +            if is_refcell_ref(cx, adt.did) {
 +                span_lint_and_note(
 +                    cx,
 +                    AWAIT_HOLDING_REFCELL_REF,
 +                    ty_cause.span,
 +                    "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await",
 +                    ty_cause.scope_span.or(Some(span)),
 +                    "these are all the await points this ref is held through",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    match_def_path(cx, def_id, &paths::MUTEX_GUARD)
 +        || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
 +        || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
 +        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
 +        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
 +        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
 +}
 +
 +fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
 +}
index 63ac8fd2dd269959f08149e2bf7c9efb36ef2efe,0000000000000000000000000000000000000000..334e1646cd4fc964b256c55d920e4dd1323b590f
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,51 @@@
-     let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::ty::is_isize_or_usize;
 +use rustc_hir::Expr;
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, FloatTy, Ty};
 +
 +use super::{utils, CAST_PRECISION_LOSS};
 +
 +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    if !cast_from.is_integral() || cast_to.is_integral() {
 +        return;
 +    }
 +
 +    let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
++    let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) {
 +        32
 +    } else {
 +        64
 +    };
 +
 +    if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) {
 +        return;
 +    }
 +
 +    let cast_to_f64 = to_nbits == 64;
 +    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 {
 +        utils::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
 +        ),
 +    );
 +}
index 15252ef96cd1d7fbaf5662eaf4615eafb54873c8,0000000000000000000000000000000000000000..fdef0abe9708e34eb7d0f800d4bbc1b10d4b54fe
mode 100644,000000..100644
--- /dev/null
@@@ -1,117 -1,0 +1,118 @@@
 +use clippy_utils::diagnostics::span_lint_and_help;
 +use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
 +use rustc_hir::{
 +    def::{DefKind, Res},
 +    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects manual `std::default::Default` implementations that are identical to a derived implementation.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is less concise.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct Foo {
 +    ///     bar: bool
 +    /// }
 +    ///
 +    /// impl std::default::Default for Foo {
 +    ///     fn default() -> Self {
 +    ///         Self {
 +    ///             bar: false
 +    ///         }
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written as:
 +    ///
 +    /// ```rust
 +    /// #[derive(Default)]
 +    /// struct Foo {
 +    ///     bar: bool
 +    /// }
 +    /// ```
 +    ///
 +    /// ### Known problems
 +    /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
 +    /// in generic types and the user defined `impl` maybe is more generalized or
 +    /// specialized than what derive will produce. This lint can't detect the manual `impl`
 +    /// has exactly equal bounds, and therefore this lint is disabled for types with
 +    /// generic parameters.
 +    ///
 +    pub DERIVABLE_IMPLS,
 +    complexity,
 +    "manual implementation of the `Default` trait which is equal to a derive"
 +}
 +
 +declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);
 +
 +fn is_path_self(e: &Expr<'_>) -> bool {
 +    if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind {
 +        matches!(p.res, Res::SelfCtor(..) | Res::Def(DefKind::Ctor(..), _))
 +    } else {
 +        false
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if_chain! {
 +            if let ItemKind::Impl(Impl {
 +                of_trait: Some(ref trait_ref),
 +                items: [child],
 +                self_ty,
 +                ..
 +            }) = item.kind;
 +            if let attrs = cx.tcx.hir().attrs(item.hir_id());
 +            if !is_automatically_derived(attrs);
 +            if !in_macro(item.span);
 +            if let Some(def_id) = trait_ref.trait_def_id();
 +            if cx.tcx.is_diagnostic_item(sym::Default, def_id);
 +            if let impl_item_hir = child.id.hir_id();
 +            if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
 +            if let ImplItemKind::Fn(_, b) = &impl_item.kind;
 +            if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
 +            if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
 +            if !attrs.iter().any(|attr| attr.doc_str().is_some());
 +            if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
 +            if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
++            if adt_def.is_struct();
 +            then {
 +                if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
 +                    if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
 +                        for arg in a.args {
 +                            if !matches!(arg, GenericArg::Lifetime(_)) {
 +                                return;
 +                            }
 +                        }
 +                    }
 +                }
 +                let should_emit = match remove_blocks(func_expr).kind {
 +                    ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
 +                    ExprKind::Call(callee, args)
 +                        if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
 +                    ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
 +                    _ => false,
 +                };
 +                if should_emit {
 +                    let path_string = cx.tcx.def_path_str(adt_def.did);
 +                    span_lint_and_help(
 +                        cx,
 +                        DERIVABLE_IMPLS,
 +                        item.span,
 +                        "this `impl` can be derived",
 +                        None,
 +                        &format!("try annotating `{}` with `#[derive(Default)]`", path_string),
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
index 8416b8440dfbe0bf99988c21d09aea8b60799d18,0000000000000000000000000000000000000000..24ac5917dcb0521350e0072234bee02982e58f7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,422 -1,0 +1,422 @@@
-             if let Unsafety::Unsafe = header.unsafety;
 +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then};
 +use clippy_utils::paths;
 +use clippy_utils::ty::{implements_trait, is_copy};
 +use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
 +use if_chain::if_chain;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `Hash` but implementing `PartialEq`
 +    /// explicitly or vice versa.
 +    ///
 +    /// ### Why is this bad?
 +    /// The implementation of these traits must agree (for
 +    /// example for use with `HashMap`) so it’s probably a bad idea to use a
 +    /// default-generated `Hash` implementation with an explicitly defined
 +    /// `PartialEq`. In particular, the following must hold for any type:
 +    ///
 +    /// ```text
 +    /// k1 == k2 ⇒ hash(k1) == hash(k2)
 +    /// ```
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// #[derive(Hash)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialEq for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    pub DERIVE_HASH_XOR_EQ,
 +    correctness,
 +    "deriving `Hash` but implementing `PartialEq` explicitly"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `Ord` but implementing `PartialOrd`
 +    /// explicitly or vice versa.
 +    ///
 +    /// ### Why is this bad?
 +    /// The implementation of these traits must agree (for
 +    /// example for use with `sort`) so it’s probably a bad idea to use a
 +    /// default-generated `Ord` implementation with an explicitly defined
 +    /// `PartialOrd`. In particular, the following must hold for any type
 +    /// implementing `Ord`:
 +    ///
 +    /// ```text
 +    /// k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
 +    /// ```
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// #[derive(Ord, PartialEq, Eq)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialOrd for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust,ignore
 +    /// #[derive(PartialEq, Eq)]
 +    /// struct Foo;
 +    ///
 +    /// impl PartialOrd for Foo {
 +    ///     fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
 +    ///        Some(self.cmp(other))
 +    ///     }
 +    /// }
 +    ///
 +    /// impl Ord for Foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    /// or, if you don't need a custom ordering:
 +    /// ```rust,ignore
 +    /// #[derive(Ord, PartialOrd, PartialEq, Eq)]
 +    /// struct Foo;
 +    /// ```
 +    pub DERIVE_ORD_XOR_PARTIAL_ORD,
 +    correctness,
 +    "deriving `Ord` but implementing `PartialOrd` explicitly"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for explicit `Clone` implementations for `Copy`
 +    /// types.
 +    ///
 +    /// ### Why is this bad?
 +    /// To avoid surprising behaviour, these traits should
 +    /// agree and the behaviour of `Copy` cannot be overridden. In almost all
 +    /// situations a `Copy` type should have a `Clone` implementation that does
 +    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
 +    /// gets you.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// #[derive(Copy)]
 +    /// struct Foo;
 +    ///
 +    /// impl Clone for Foo {
 +    ///     // ..
 +    /// }
 +    /// ```
 +    pub EXPL_IMPL_CLONE_ON_COPY,
 +    pedantic,
 +    "implementing `Clone` explicitly on `Copy` types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for deriving `serde::Deserialize` on a type that
 +    /// has methods using `unsafe`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Deriving `serde::Deserialize` will create a constructor
 +    /// that may violate invariants hold by another constructor.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// use serde::Deserialize;
 +    ///
 +    /// #[derive(Deserialize)]
 +    /// pub struct Foo {
 +    ///     // ..
 +    /// }
 +    ///
 +    /// impl Foo {
 +    ///     pub fn new() -> Self {
 +    ///         // setup here ..
 +    ///     }
 +    ///
 +    ///     pub unsafe fn parts() -> (&str, &str) {
 +    ///         // assumes invariants hold
 +    ///     }
 +    /// }
 +    /// ```
 +    pub UNSAFE_DERIVE_DESERIALIZE,
 +    pedantic,
 +    "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
 +}
 +
 +declare_lint_pass!(Derive => [
 +    EXPL_IMPL_CLONE_ON_COPY,
 +    DERIVE_HASH_XOR_EQ,
 +    DERIVE_ORD_XOR_PARTIAL_ORD,
 +    UNSAFE_DERIVE_DESERIALIZE
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Derive {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Impl(Impl {
 +            of_trait: Some(ref trait_ref),
 +            ..
 +        }) = item.kind
 +        {
 +            let ty = cx.tcx.type_of(item.def_id);
 +            let attrs = cx.tcx.hir().attrs(item.hir_id());
 +            let is_automatically_derived = is_automatically_derived(attrs);
 +
 +            check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
 +            check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
 +
 +            if is_automatically_derived {
 +                check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
 +            } else {
 +                check_copy_clone(cx, item, trait_ref, ty);
 +            }
 +        }
 +    }
 +}
 +
 +/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
 +fn check_hash_peq<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    trait_ref: &TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +    hash_is_automatically_derived: bool,
 +) {
 +    if_chain! {
 +        if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
 +        if let Some(def_id) = trait_ref.trait_def_id();
 +        if match_def_path(cx, def_id, &paths::HASH);
 +        then {
 +            // Look for the PartialEq implementations for `ty`
 +            cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
 +                let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
 +
 +                if peq_is_automatically_derived == hash_is_automatically_derived {
 +                    return;
 +                }
 +
 +                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
 +
 +                // Only care about `impl PartialEq<Foo> for Foo`
 +                // For `impl PartialEq<B> for A, input_types is [A, B]
 +                if trait_ref.substs.type_at(1) == ty {
 +                    let mess = if peq_is_automatically_derived {
 +                        "you are implementing `Hash` explicitly but have derived `PartialEq`"
 +                    } else {
 +                        "you are deriving `Hash` but have implemented `PartialEq` explicitly"
 +                    };
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        DERIVE_HASH_XOR_EQ,
 +                        span,
 +                        mess,
 +                        |diag| {
 +                            if let Some(local_def_id) = impl_id.as_local() {
 +                                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +                                diag.span_note(
 +                                    cx.tcx.hir().span(hir_id),
 +                                    "`PartialEq` implemented here"
 +                                );
 +                            }
 +                        }
 +                    );
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
 +fn check_ord_partial_ord<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    trait_ref: &TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +    ord_is_automatically_derived: bool,
 +) {
 +    if_chain! {
 +        if let Some(ord_trait_def_id) = get_trait_def_id(cx, &paths::ORD);
 +        if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait();
 +        if let Some(def_id) = &trait_ref.trait_def_id();
 +        if *def_id == ord_trait_def_id;
 +        then {
 +            // Look for the PartialOrd implementations for `ty`
 +            cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
 +                let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
 +
 +                if partial_ord_is_automatically_derived == ord_is_automatically_derived {
 +                    return;
 +                }
 +
 +                let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
 +
 +                // Only care about `impl PartialOrd<Foo> for Foo`
 +                // For `impl PartialOrd<B> for A, input_types is [A, B]
 +                if trait_ref.substs.type_at(1) == ty {
 +                    let mess = if partial_ord_is_automatically_derived {
 +                        "you are implementing `Ord` explicitly but have derived `PartialOrd`"
 +                    } else {
 +                        "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
 +                    };
 +
 +                    span_lint_and_then(
 +                        cx,
 +                        DERIVE_ORD_XOR_PARTIAL_ORD,
 +                        span,
 +                        mess,
 +                        |diag| {
 +                            if let Some(local_def_id) = impl_id.as_local() {
 +                                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +                                diag.span_note(
 +                                    cx.tcx.hir().span(hir_id),
 +                                    "`PartialOrd` implemented here"
 +                                );
 +                            }
 +                        }
 +                    );
 +                }
 +            });
 +        }
 +    }
 +}
 +
 +/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
 +fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
 +    let clone_id = match cx.tcx.lang_items().clone_trait() {
 +        Some(id) if trait_ref.trait_def_id() == Some(id) => id,
 +        _ => return,
 +    };
 +    let copy_id = match cx.tcx.lang_items().copy_trait() {
 +        Some(id) => id,
 +        None => return,
 +    };
 +    let (ty_adt, ty_subs) = match *ty.kind() {
 +        // Unions can't derive clone.
 +        ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
 +        _ => return,
 +    };
 +    // If the current self type doesn't implement Copy (due to generic constraints), search to see if
 +    // there's a Copy impl for any instance of the adt.
 +    if !is_copy(cx, ty) {
 +        if ty_subs.non_erasable_generics().next().is_some() {
 +            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
 +                impls
 +                    .iter()
 +                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
 +            });
 +            if !has_copy_impl {
 +                return;
 +            }
 +        } else {
 +            return;
 +        }
 +    }
 +    // Derive constrains all generic types to requiring Clone. Check if any type is not constrained for
 +    // this impl.
 +    if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
 +        return;
 +    }
 +
 +    span_lint_and_note(
 +        cx,
 +        EXPL_IMPL_CLONE_ON_COPY,
 +        item.span,
 +        "you are implementing `Clone` explicitly on a `Copy` type",
 +        Some(item.span),
 +        "consider deriving `Clone` or removing `Copy`",
 +    );
 +}
 +
 +/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint.
 +fn check_unsafe_derive_deserialize<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    item: &Item<'_>,
 +    trait_ref: &TraitRef<'_>,
 +    ty: Ty<'tcx>,
 +) {
 +    fn item_from_def_id<'tcx>(cx: &LateContext<'tcx>, def_id: DefId) -> &'tcx Item<'tcx> {
 +        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
 +        cx.tcx.hir().expect_item(hir_id)
 +    }
 +
 +    fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
 +        let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
 +        walk_item(&mut visitor, item);
 +        visitor.has_unsafe
 +    }
 +
 +    if_chain! {
 +        if let Some(trait_def_id) = trait_ref.trait_def_id();
 +        if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE);
 +        if let ty::Adt(def, _) = ty.kind();
 +        if let Some(local_def_id) = def.did.as_local();
 +        let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
 +        if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
 +        if cx.tcx.inherent_impls(def.did)
 +            .iter()
 +            .map(|imp_did| item_from_def_id(cx, *imp_did))
 +            .any(|imp| has_unsafe(cx, imp));
 +        then {
 +            span_lint_and_help(
 +                cx,
 +                UNSAFE_DERIVE_DESERIALIZE,
 +                item.span,
 +                "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
 +                None,
 +                "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html"
 +            );
 +        }
 +    }
 +}
 +
 +struct UnsafeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    has_unsafe: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, span: Span, id: HirId) {
 +        if self.has_unsafe {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let Some(header) = kind.header();
-             if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules {
++            if header.unsafety == Unsafety::Unsafe;
 +            then {
 +                self.has_unsafe = true;
 +            }
 +        }
 +
 +        walk_fn(self, kind, decl, body_id, span, id);
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.has_unsafe {
 +            return;
 +        }
 +
 +        if let ExprKind::Block(block, _) = expr.kind {
++            if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
 +                self.has_unsafe = true;
 +            }
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +}
index 33ed6273ad2c5aa731b2f4e277ba33415c47f6a1,0000000000000000000000000000000000000000..9840affbf6fd81b978a00e2e17a0d1a0a564690c
mode 100644,000000..100644
--- /dev/null
@@@ -1,785 -1,0 +1,807 @@@
-             _ => {},
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
 +use clippy_utils::source::first_line_of_span;
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 +use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
 +use if_chain::if_chain;
 +use itertools::Itertools;
 +use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, 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_hir::intravisit::{self, NestedVisitorMap, Visitor};
 +use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_parse::maybe_new_parser_from_source_str;
 +use rustc_parse::parser::ForceCollect;
 +use rustc_session::parse::ParseSess;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::def_id::LocalDefId;
 +use rustc_span::edition::Edition;
 +use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
 +use rustc_span::{sym, FileName, Pos};
 +use std::io;
 +use std::ops::Range;
 +use std::thread;
 +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. HTML elements and their
 +    /// content are not linted.
 +    ///
 +    /// In addition, when writing documentation comments, including `[]` brackets
 +    /// inside a link text would trip the parser. Therfore, documenting link with
 +    /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
 +    /// would fail.
 +    ///
 +    /// ### 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) {}
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// // Link text with `[]` brackets should be written as following:
 +    /// /// Consume the array and return the inner
 +    /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
 +    /// /// [SmallVec]: SmallVec
 +    /// fn main() {}
 +    /// ```
 +    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.
 +    ///
 +    /// ### 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.
 +    ///
 +    /// ### 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 the doc comments of publicly visible functions that
 +    /// may panic and warns if there is no `# Panics` section.
 +    ///
 +    /// ### Why is this bad?
 +    /// Documenting the scenarios in which panicking occurs
 +    /// can help callers who do not want to panic to avoid those situations.
 +    ///
 +    /// ### Examples
 +    /// Since the following function may panic it has a `# Panics` section in
 +    /// its doc comment:
 +    ///
 +    /// ```rust
 +    /// /// # Panics
 +    /// ///
 +    /// /// Will panic if y is 0
 +    /// pub fn divide_by(x: i32, y: i32) -> i32 {
 +    ///     if y == 0 {
 +    ///         panic!("Cannot divide by 0")
 +    ///     } else {
 +    ///         x / y
 +    ///     }
 +    /// }
 +    /// ```
 +    pub MISSING_PANICS_DOC,
 +    pedantic,
 +    "`pub fn` may panic without `# Panics` 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.
 +    ///
 +    /// ### 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, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN]
 +);
 +
 +impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
 +    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
 +        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
 +        check_attrs(cx, &self.valid_idents, attrs);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, attrs);
 +        match item.kind {
 +            hir::ItemKind::Fn(ref sig, _, body_id) => {
 +                if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
 +                    let body = cx.tcx.hir().body(body_id);
 +                    let mut fpu = FindPanicUnwrap {
 +                        cx,
 +                        typeck_results: cx.tcx.typeck(item.def_id),
 +                        panic_span: None,
 +                    };
 +                    fpu.visit_expr(&body.value);
 +                    lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
 +                }
 +            },
 +            hir::ItemKind::Impl(ref impl_) => {
 +                self.in_trait_impl = impl_.of_trait.is_some();
 +            },
-     let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
++            hir::ItemKind::Trait(_, unsafety, ..) => {
++                if !headers.safety && unsafety == hir::Unsafety::Unsafe {
++                    span_lint(
++                        cx,
++                        MISSING_SAFETY_DOC,
++                        item.span,
++                        "docs for unsafe trait missing `# Safety` section",
++                    );
++                }
++            },
++            _ => (),
 +        }
 +    }
 +
 +    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 attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, 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.def_id, item.span, sig, headers, None, None);
 +            }
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, 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 {
 +            let body = cx.tcx.hir().body(body_id);
 +            let mut fpu = FindPanicUnwrap {
 +                cx,
 +                typeck_results: cx.tcx.typeck(item.def_id),
 +                panic_span: None,
 +            };
 +            fpu.visit_expr(&body.value);
 +            lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
 +        }
 +    }
 +}
 +
 +fn lint_for_missing_headers<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    def_id: LocalDefId,
 +    span: impl Into<MultiSpan> + Copy,
 +    sig: &hir::FnSig<'_>,
 +    headers: DocHeaders,
 +    body_id: Option<hir::BodyId>,
 +    panic_span: Option<Span>,
 +) {
 +    if !cx.access_levels.is_exported(def_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.panics && panic_span.is_some() {
 +        span_lint_and_note(
 +            cx,
 +            MISSING_PANICS_DOC,
 +            span,
 +            "docs for function which may panic missing `# Panics` section",
 +            panic_span,
 +            "first possible panic found here",
 +        );
 +    }
 +    if !headers.errors {
 +        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
 +        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
 +            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 typeck = cx.tcx.typeck_body(body_id);
 +                let body = cx.tcx.hir().body(body_id);
 +                let ret_ty = typeck.expr_ty(&body.value);
 +                if implements_trait(cx, ret_ty, future, &[]);
 +                if let ty::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);
 +                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();
 +        for c in &mut chars {
 +            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,
 +    panics: bool,
 +}
 +
 +fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
++    use pulldown_cmark::{BrokenLink, CowStr, Options};
++    /// We don't want the parser to choke on intra doc links. Since we don't
++    /// actually care about rendering them, just pretend that all broken links are
++    /// point to a fake address.
++    #[allow(clippy::unnecessary_wraps)] // we're following a type signature
++    fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
++        Some(("fake".into(), "fake".into()))
++    }
++
 +    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,
 +                panics: 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,
 +            panics: false,
 +        };
 +    }
 +
++    let mut cb = fake_broken_link_callback;
++
++    let parser =
++        pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).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"];
 +
 +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::Event::{
 +        Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 +    };
 +    use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
 +    use pulldown_cmark::{CodeBlockKind, CowStr};
 +
 +    let mut headers = DocHeaders {
 +        safety: false,
 +        errors: false,
 +        panics: false,
 +    };
 +    let mut in_code = false;
 +    let mut in_link = None;
 +    let mut in_heading = false;
 +    let mut is_rust = false;
 +    let mut edition = None;
 +    let mut ticks_unbalanced = false;
 +    let mut text_to_check: Vec<(CowStr<'_>, Span)> = Vec::new();
 +    let mut paragraph_span = spans.get(0).expect("function isn't called if doc comment is empty").1;
 +    for (event, range) in events {
 +        match event {
 +            Start(CodeBlock(ref kind)) => {
 +                in_code = true;
 +                if let CodeBlockKind::Fenced(lang) = kind {
 +                    for item in lang.split(',') {
 +                        if item == "ignore" {
 +                            is_rust = false;
 +                            break;
 +                        }
 +                        if let Some(stripped) = item.strip_prefix("edition") {
 +                            is_rust = true;
 +                            edition = stripped.parse::<Edition>().ok();
 +                        } else if item.is_empty() || RUST_CODE.contains(&item) {
 +                            is_rust = true;
 +                        }
 +                    }
 +                }
 +            },
 +            End(CodeBlock(_)) => {
 +                in_code = false;
 +                is_rust = false;
 +            },
 +            Start(Link(_, url, _)) => in_link = Some(url),
 +            End(Link(..)) => in_link = None,
 +            Start(Heading(_) | Paragraph | Item) => {
 +                if let Start(Heading(_)) = event {
 +                    in_heading = true;
 +                }
 +                ticks_unbalanced = false;
 +                let (_, span) = get_current_span(spans, range.start);
 +                paragraph_span = first_line_of_span(cx, span);
 +            },
 +            End(Heading(_) | Paragraph | Item) => {
 +                if let End(Heading(_)) = event {
 +                    in_heading = false;
 +                }
 +                if ticks_unbalanced {
 +                    span_lint_and_help(
 +                        cx,
 +                        DOC_MARKDOWN,
 +                        paragraph_span,
 +                        "backticks are unbalanced",
 +                        None,
 +                        "a backtick may be missing a pair",
 +                    );
 +                } else {
 +                    for (text, span) in text_to_check {
 +                        check_text(cx, valid_idents, &text, span);
 +                    }
 +                }
 +                text_to_check = Vec::new();
 +            },
 +            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) => {
 +                let (begin, span) = get_current_span(spans, range.start);
 +                paragraph_span = paragraph_span.with_hi(span.hi());
 +                ticks_unbalanced |= text.contains('`') && !in_code;
 +                if Some(&text) == in_link.as_ref() || ticks_unbalanced {
 +                    // 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";
 +                headers.panics |= in_heading && text.trim() == "Panics";
 +                if in_code {
 +                    if is_rust {
 +                        let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
 +                        check_code(cx, &text, edition, span);
 +                    }
 +                } else {
 +                    // Adjust for the beginning of the current `Event`
 +                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
 +                    text_to_check.push((text, span));
 +                }
 +            },
 +        }
 +    }
 +    headers
 +}
 +
 +fn get_current_span(spans: &[(usize, Span)], idx: usize) -> (usize, Span) {
 +    let index = match spans.binary_search_by(|c| c.0.cmp(&idx)) {
 +        Ok(o) => o,
 +        Err(e) => e - 1,
 +    };
 +    spans[index]
 +}
 +
 +fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
 +    fn has_needless_main(code: String, edition: Edition) -> bool {
 +        rustc_driver::catch_fatal_errors(|| {
 +            rustc_span::create_session_globals_then(edition, || {
 +                let filename = FileName::anon_source_code(&code);
 +
 +                let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
 +                let emitter = EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false);
 +                let handler = Handler::with_emitter(false, None, Box::new(emitter));
 +                let sess = ParseSess::with_span_handler(handler, sm);
 +
 +                let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
 +                    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(ForceCollect::No) {
 +                        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(box FnKind(_, 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,
 +                                    FnRetTy::Ty(_) => 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
 +            })
 +        })
 +        .ok()
 +        .unwrap_or_default()
 +    }
 +
 +    // Because of the global session, we need to create a new session in a different thread with
 +    // the edition we need.
 +    let text = text.to_owned();
 +    if thread::spawn(move || has_needless_main(text, edition))
 +        .join()
 +        .expect("thread::spawn failed")
 +    {
 +        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(),
 +            span.parent(),
 +        );
 +
 +        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 = s.strip_suffix('s').unwrap_or(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),
 +        );
 +    }
 +}
 +
 +struct FindPanicUnwrap<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    panic_span: Option<Span>,
 +    typeck_results: &'tcx ty::TypeckResults<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.panic_span.is_some() {
 +            return;
 +        }
 +
 +        // check for `begin_panic`
 +        if_chain! {
 +            if let ExprKind::Call(func_expr, _) = expr.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
 +            if let Some(path_def_id) = path.res.opt_def_id();
 +            if match_panic_def_id(self.cx, path_def_id);
 +            if is_expn_of(expr.span, "unreachable").is_none();
 +            if !is_expn_of_debug_assertions(expr.span);
 +            then {
 +                self.panic_span = Some(expr.span);
 +            }
 +        }
 +
 +        // check for `assert_eq` or `assert_ne`
 +        if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
 +            self.panic_span = Some(expr.span);
 +        }
 +
 +        // check for `unwrap`
 +        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
 +            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
 +            if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
 +                || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
 +            {
 +                self.panic_span = Some(expr.span);
 +            }
 +        }
 +
 +        // and check sub-expressions
 +        intravisit::walk_expr(self, expr);
 +    }
 +
 +    // Panics in const blocks will cause compilation to fail.
 +    fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +fn is_expn_of_debug_assertions(span: Span) -> bool {
 +    const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
 +    MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0c6ba91c9430b9db1024c62276d96dab17b4a3d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,100 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::source::snippet_with_applicability;
++use clippy_utils::ty::implements_trait;
++use if_chain::if_chain;
++use rustc_errors::Applicability;
++use rustc_hir::{Expr, ExprKind, Pat, PatKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::ty::Ty;
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for pattern matchings that can be expressed using equality.
++    ///
++    /// ### Why is this bad?
++    ///
++    /// * It reads better and has less cognitive load because equality won't cause binding.
++    /// * It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely
++    /// criticized for increasing the cognitive load of reading the code.
++    /// * Equality is a simple bool expression and can be merged with `&&` and `||` and
++    /// reuse if blocks
++    ///
++    /// ### Example
++    /// ```rust,ignore
++    /// if let Some(2) = x {
++    ///     do_thing();
++    /// }
++    /// ```
++    /// Should be written
++    /// ```rust,ignore
++    /// if x == Some(2) {
++    ///     do_thing();
++    /// }
++    /// ```
++    pub EQUATABLE_IF_LET,
++    nursery,
++    "using pattern matching instead of equality"
++}
++
++declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]);
++
++/// detects if pattern matches just one thing
++fn unary_pattern(pat: &Pat<'_>) -> bool {
++    fn array_rec(pats: &[Pat<'_>]) -> bool {
++        pats.iter().all(unary_pattern)
++    }
++    match &pat.kind {
++        PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
++            false
++        },
++        PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
++        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
++        PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
++        PatKind::Path(_) | PatKind::Lit(_) => true,
++    }
++}
++
++fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
++    if let Some(def_id) = cx.tcx.lang_items().eq_trait() {
++        implements_trait(cx, ty, def_id, &[other.into()])
++    } else {
++        false
++    }
++}
++
++impl<'tcx> LateLintPass<'tcx> for PatternEquality {
++    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
++        if_chain! {
++            if let ExprKind::Let(pat, exp, _) = expr.kind;
++            if unary_pattern(pat);
++            let exp_ty = cx.typeck_results().expr_ty(exp);
++            let pat_ty = cx.typeck_results().pat_ty(pat);
++            if is_structural_partial_eq(cx, exp_ty, pat_ty);
++            then {
++
++                let mut applicability = Applicability::MachineApplicable;
++                let pat_str = match pat.kind {
++                    PatKind::Struct(..) => format!(
++                        "({})",
++                        snippet_with_applicability(cx, pat.span, "..", &mut applicability),
++                    ),
++                    _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
++                };
++                span_lint_and_sugg(
++                    cx,
++                    EQUATABLE_IF_LET,
++                    expr.span,
++                    "this pattern matching can be expressed using equality",
++                    "try",
++                    format!(
++                        "{} == {}",
++                        snippet_with_applicability(cx, exp.span, "..", &mut applicability),
++                        pat_str,
++                    ),
++                    applicability,
++                );
++            }
++        }
++    }
++}
index 026d14d0ea265f445d0ffcb3c23c5afcda86a593,0000000000000000000000000000000000000000..d0944c37cf5f76b42948e55fe2e18070fc6681c4
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
-     if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) {
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::span_lint;
 +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;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for erasing operations, e.g., `x * 0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The whole expression can be replaced by zero.
 +    /// This is most likely not the intended outcome and should probably be
 +    /// corrected
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 1;
 +    /// 0 / x;
 +    /// 0 * x;
 +    /// x & 0;
 +    /// ```
 +    pub ERASING_OP,
 +    correctness,
 +    "using erasing operations, e.g., `x * 0` or `y & 0`"
 +}
 +
 +declare_lint_pass!(ErasingOp => [ERASING_OP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ErasingOp {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::Binary(ref cmp, left, right) = e.kind {
 +            match cmp.node {
 +                BinOpKind::Mul | BinOpKind::BitAnd => {
 +                    check(cx, left, e.span);
 +                    check(cx, right, e.span);
 +                },
 +                BinOpKind::Div => check(cx, left, e.span),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) {
++    if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) {
 +        span_lint(
 +            cx,
 +            ERASING_OP,
 +            span,
 +            "this operation will always return zero. This is likely not the intended outcome",
 +        );
 +    }
 +}
index 090be73af3b7a9f073f6ced9cf7cb598d02f5c1b,0000000000000000000000000000000000000000..75b1c882c233628ca4e4fd89f769dc1fc25b6e81
mode 100644,000000..100644
--- /dev/null
@@@ -1,202 -1,0 +1,202 @@@
-                         if let AssocItemKind::Fn { has_self: true } = trait_item.kind {
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::ty::contains_ty;
 +use rustc_hir::intravisit;
 +use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::mir::FakeReadCause;
 +use rustc_middle::ty::layout::LayoutOf;
 +use rustc_middle::ty::{self, TraitRef, Ty};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::kw;
 +use rustc_target::spec::abi::Abi;
 +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 +
 +#[derive(Copy, Clone)]
 +pub struct BoxedLocal {
 +    pub too_large_for_stack: u64,
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `Box<T>` where an unboxed `T` would
 +    /// work fine.
 +    ///
 +    /// ### Why is this bad?
 +    /// This is an unnecessary allocation, and bad for
 +    /// performance. It is only necessary to allocate if you wish to move the box
 +    /// into something.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn foo(bar: usize) {}
 +    /// // Bad
 +    /// let x = Box::new(1);
 +    /// foo(*x);
 +    /// println!("{}", *x);
 +    ///
 +    /// // Good
 +    /// let x = 1;
 +    /// foo(x);
 +    /// println!("{}", x);
 +    /// ```
 +    pub BOXED_LOCAL,
 +    perf,
 +    "using `Box<T>` where unnecessary"
 +}
 +
 +fn is_non_trait_box(ty: Ty<'_>) -> bool {
 +    ty.is_box() && !ty.boxed_ty().is_trait()
 +}
 +
 +struct EscapeDelegate<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    set: HirIdSet,
 +    trait_self_ty: Option<Ty<'tcx>>,
 +    too_large_for_stack: u64,
 +}
 +
 +impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]);
 +
 +impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        fn_kind: intravisit::FnKind<'tcx>,
 +        _: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        _: Span,
 +        hir_id: HirId,
 +    ) {
 +        if let Some(header) = fn_kind.header() {
 +            if header.abi != Abi::Rust {
 +                return;
 +            }
 +        }
 +
 +        let parent_id = cx.tcx.hir().get_parent_item(hir_id);
 +        let parent_node = cx.tcx.hir().find(parent_id);
 +
 +        let mut trait_self_ty = None;
 +        if let Some(Node::Item(item)) = parent_node {
 +            // If the method is an impl for a trait, don't warn.
 +            if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = item.kind {
 +                return;
 +            }
 +
 +            // find `self` ty for this trait if relevant
 +            if let ItemKind::Trait(_, _, _, _, items) = item.kind {
 +                for trait_item in items {
 +                    if trait_item.id.hir_id() == hir_id {
 +                        // be sure we have `self` parameter in this function
++                        if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
 +                            trait_self_ty = Some(
 +                                TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id())
 +                                    .self_ty()
 +                                    .skip_binder(),
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        let mut v = EscapeDelegate {
 +            cx,
 +            set: HirIdSet::default(),
 +            trait_self_ty,
 +            too_large_for_stack: self.too_large_for_stack,
 +        };
 +
 +        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 +        cx.tcx.infer_ctxt().enter(|infcx| {
 +            ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
 +        });
 +
 +        for node in v.set {
 +            span_lint(
 +                cx,
 +                BOXED_LOCAL,
 +                cx.tcx.hir().span(node),
 +                "local variable doesn't need to be boxed here",
 +            );
 +        }
 +    }
 +}
 +
 +// TODO: Replace with Map::is_argument(..) when it's fixed
 +fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
 +    match map.find(id) {
 +        Some(Node::Binding(_)) => (),
 +        _ => return false,
 +    }
 +
 +    matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_)))
 +}
 +
 +impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
 +    fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
 +        if cmt.place.projections.is_empty() {
 +            if let PlaceBase::Local(lid) = cmt.place.base {
 +                self.set.remove(&lid);
 +                let map = &self.cx.tcx.hir();
 +                if let Some(Node::Binding(_)) = map.find(cmt.hir_id) {
 +                    if self.set.contains(&lid) {
 +                        // let y = x where x is known
 +                        // remove x, insert y
 +                        self.set.insert(cmt.hir_id);
 +                        self.set.remove(&lid);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
 +        if cmt.place.projections.is_empty() {
 +            if let PlaceBase::Local(lid) = cmt.place.base {
 +                self.set.remove(&lid);
 +            }
 +        }
 +    }
 +
 +    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
 +        if cmt.place.projections.is_empty() {
 +            let map = &self.cx.tcx.hir();
 +            if is_argument(*map, cmt.hir_id) {
 +                // Skip closure arguments
 +                let parent_id = map.get_parent_node(cmt.hir_id);
 +                if let Some(Node::Expr(..)) = map.find(map.get_parent_node(parent_id)) {
 +                    return;
 +                }
 +
 +                // skip if there is a `self` parameter binding to a type
 +                // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
 +                if let Some(trait_self_ty) = self.trait_self_ty {
 +                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty)
 +                    {
 +                        return;
 +                    }
 +                }
 +
 +                if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) {
 +                    self.set.insert(cmt.hir_id);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
 +}
 +
 +impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
 +    fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
 +        // Large types need to be boxed to avoid stack overflows.
 +        if ty.is_box() {
 +            self.cx.layout_of(ty.boxed_ty()).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
 +        } else {
 +            false
 +        }
 +    }
 +}
index 9df92cc5b640667faf06c1f63dcf3b3b634d7541,0000000000000000000000000000000000000000..765a6c7585a20a6ee3b5f4d09bd6f5b0319396ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,215 @@@
-                             if let ClosureKind::FnMut = substs.as_closure().kind();
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::higher::VecArgs;
 +use clippy_utils::source::snippet_opt;
 +use clippy_utils::usage::UsedAfterExprVisitor;
 +use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::subst::Subst;
 +use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for closures which just call another function where
 +    /// the function can be called directly. `unsafe` functions or calls where types
 +    /// get adjusted are ignored.
 +    ///
 +    /// ### Why is this bad?
 +    /// Needlessly creating a closure adds code for no benefit
 +    /// and gives the optimizer more work.
 +    ///
 +    /// ### Known problems
 +    /// If creating the closure inside the closure has a side-
 +    /// effect then moving the closure creation out will change when that side-
 +    /// effect runs.
 +    /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// xs.map(|x| foo(x))
 +    ///
 +    /// // Good
 +    /// xs.map(foo)
 +    /// ```
 +    /// where `foo(_)` is a plain function that takes the exact argument type of
 +    /// `x`.
 +    pub REDUNDANT_CLOSURE,
 +    style,
 +    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for closures which only invoke a method on the closure
 +    /// argument and can be replaced by referencing the method directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's unnecessary to create the closure.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// Some('a').map(|s| s.to_uppercase());
 +    /// ```
 +    /// may be rewritten as
 +    /// ```rust,ignore
 +    /// Some('a').map(char::to_uppercase);
 +    /// ```
 +    pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
 +    pedantic,
 +    "redundant closures for method calls"
 +}
 +
 +declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for EtaReduction {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +        let body = match expr.kind {
 +            ExprKind::Closure(_, _, id, _, _) => cx.tcx.hir().body(id),
 +            _ => return,
 +        };
 +        if body.value.span.from_expansion() {
 +            if body.params.is_empty() {
 +                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
 +                    // replace `|| vec![]` with `Vec::new`
 +                    span_lint_and_sugg(
 +                        cx,
 +                        REDUNDANT_CLOSURE,
 +                        expr.span,
 +                        "redundant closure",
 +                        "replace the closure with `Vec::new`",
 +                        "std::vec::Vec::new".into(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +            // skip `foo(|| macro!())`
 +            return;
 +        }
 +
 +        let closure_ty = cx.typeck_results().expr_ty(expr);
 +
 +        if_chain!(
 +            if let ExprKind::Call(callee, args) = body.value.kind;
 +            if let ExprKind::Path(_) = callee.kind;
 +            if check_inputs(cx, body.params, args);
 +            let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
 +            let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
 +                .map_or(callee_ty, |id| cx.tcx.type_of(id));
 +            if check_sig(cx, closure_ty, call_ty);
 +            let substs = cx.typeck_results().node_substs(callee.hir_id);
 +            // This fixes some false positives that I don't entirely understand
 +            if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
 +            // A type param function ref like `T::f` is not 'static, however
 +            // it is if cast like `T::f as fn()`. This seems like a rustc bug.
 +            if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
 +            then {
 +                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
 +                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
 +                        if_chain! {
 +                            if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
++                            if substs.as_closure().kind() == ClosureKind::FnMut;
 +                            if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
 +                                || UsedAfterExprVisitor::is_found(cx, callee);
 +
 +                            then {
 +                                // Mutable closure is used after current expr; we cannot consume it.
 +                                snippet = format!("&mut {}", snippet);
 +                            }
 +                        }
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "replace the closure with the function itself",
 +                            snippet,
 +                            Applicability::MachineApplicable,
 +                        );
 +                    }
 +                });
 +            }
 +        );
 +
 +        if_chain!(
 +            if let ExprKind::MethodCall(path, _, args, _) = body.value.kind;
 +            if check_inputs(cx, body.params, args);
 +            let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
 +            let substs = cx.typeck_results().node_substs(body.value.hir_id);
 +            let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
 +            if check_sig(cx, closure_ty, call_ty);
 +            then {
 +                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
 +                    let name = get_ufcs_type_name(cx, method_def_id);
 +                    diag.span_suggestion(
 +                        expr.span,
 +                        "replace the closure with the method itself",
 +                        format!("{}::{}", name, path.ident.name),
 +                        Applicability::MachineApplicable,
 +                    );
 +                })
 +            }
 +        );
 +    }
 +}
 +
 +fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
 +    if params.len() != call_args.len() {
 +        return false;
 +    }
 +    std::iter::zip(params, call_args).all(|(param, arg)| {
 +        match param.pat.kind {
 +            PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
 +            _ => return false,
 +        }
 +        match *cx.typeck_results().expr_adjustments(arg) {
 +            [] => true,
 +            [Adjustment {
 +                kind: Adjust::Deref(None),
 +                ..
 +            }, Adjustment {
 +                kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
 +                ..
 +            }] => {
 +                // re-borrow with the same mutability is allowed
 +                let ty = cx.typeck_results().expr_ty(arg);
 +                matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
 +            },
 +            _ => false,
 +        }
 +    })
 +}
 +
 +fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
 +    let call_sig = call_ty.fn_sig(cx.tcx);
 +    if call_sig.unsafety() == Unsafety::Unsafe {
 +        return false;
 +    }
 +    if !closure_ty.has_late_bound_regions() {
 +        return true;
 +    }
 +    let substs = match closure_ty.kind() {
 +        ty::Closure(_, substs) => substs,
 +        _ => return false,
 +    };
 +    let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
 +    cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
 +}
 +
 +fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
 +    match cx.tcx.associated_item(method_def_id).container {
 +        ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
 +        ty::ImplContainer(def_id) => {
 +            let ty = cx.tcx.type_of(def_id);
 +            match ty.kind() {
 +                ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did),
 +                _ => ty.to_string(),
 +            }
 +        },
 +    }
 +}
index 8714ce90164c8e3808a43192d4d979e854cab4ea,0000000000000000000000000000000000000000..1b56dd4b081775c685de8a295d1ce6c715f02ed3
mode 100644,000000..100644
--- /dev/null
@@@ -1,357 -1,0 +1,357 @@@
-                         if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() {
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 +use if_chain::if_chain;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for a read and a write to the same variable where
 +    /// whether the read occurs before or after the write depends on the evaluation
 +    /// order of sub-expressions.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
 +    /// the operands of these expressions are evaluated before applying the effects of the expression.
 +    ///
 +    /// ### Known problems
 +    /// Code which intentionally depends on the evaluation
 +    /// order, or which is correct for any evaluation order.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut x = 0;
 +    ///
 +    /// // Bad
 +    /// let a = {
 +    ///     x = 1;
 +    ///     1
 +    /// } + x;
 +    /// // Unclear whether a is 1 or 2.
 +    ///
 +    /// // Good
 +    /// let tmp = {
 +    ///     x = 1;
 +    ///     1
 +    /// };
 +    /// let a = tmp + x;
 +    /// ```
 +    pub EVAL_ORDER_DEPENDENCE,
 +    suspicious,
 +    "whether a variable read occurs before a write depends on sub-expression evaluation order"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for diverging calls that are not match arms or
 +    /// statements.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is often confusing to read. In addition, the
 +    /// sub-expression evaluation order for Rust is not well documented.
 +    ///
 +    /// ### Known problems
 +    /// Someone might want to use `some_bool || panic!()` as a
 +    /// shorthand.
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// # fn b() -> bool { true }
 +    /// # fn c() -> bool { true }
 +    /// let a = b() || panic!() || c();
 +    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
 +    /// let x = (a, b, c, panic!());
 +    /// // can simply be replaced by `panic!()`
 +    /// ```
 +    pub DIVERGING_SUB_EXPRESSION,
 +    complexity,
 +    "whether an expression contains a diverging sub expression"
 +}
 +
 +declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]);
 +
 +impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // Find a write to a local variable.
 +        let var = if_chain! {
 +            if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind;
 +            if let Some(var) = path_to_local(lhs);
 +            if expr.span.desugaring_kind().is_none();
 +            then { var } else { return; }
 +        };
 +        let mut visitor = ReadVisitor {
 +            cx,
 +            var,
 +            write_expr: expr,
 +            last_expr: expr,
 +        };
 +        check_for_unsequenced_reads(&mut visitor);
 +    }
 +    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
 +        match stmt.kind {
 +            StmtKind::Local(local) => {
 +                if let Local { init: Some(e), .. } = local {
 +                    DivergenceVisitor { cx }.visit_expr(e);
 +                }
 +            },
 +            StmtKind::Expr(e) | StmtKind::Semi(e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
 +            StmtKind::Item(..) => {},
 +        }
 +    }
 +}
 +
 +struct DivergenceVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
 +    fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
 +        match e.kind {
 +            ExprKind::Closure(..) => {},
 +            ExprKind::Match(e, arms, _) => {
 +                self.visit_expr(e);
 +                for arm in arms {
 +                    if let Some(Guard::If(if_expr)) = arm.guard {
 +                        self.visit_expr(if_expr);
 +                    }
 +                    // make sure top level arm expressions aren't linted
 +                    self.maybe_walk_expr(&*arm.body);
 +                }
 +            },
 +            _ => walk_expr(self, e),
 +        }
 +    }
 +    fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
 +        span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +        match e.kind {
 +            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
 +            ExprKind::Call(func, _) => {
 +                let typ = self.cx.typeck_results().expr_ty(func);
 +                match typ.kind() {
 +                    ty::FnDef(..) | ty::FnPtr(_) => {
 +                        let sig = typ.fn_sig(self.cx.tcx);
++                        if self.cx.tcx.erase_late_bound_regions(sig).output().kind() == &ty::Never {
 +                            self.report_diverging_sub_expr(e);
 +                        }
 +                    },
 +                    _ => {},
 +                }
 +            },
 +            ExprKind::MethodCall(..) => {
 +                let borrowed_table = self.cx.typeck_results();
 +                if borrowed_table.expr_ty(e).is_never() {
 +                    self.report_diverging_sub_expr(e);
 +                }
 +            },
 +            _ => {
 +                // do not lint expressions referencing objects of type `!`, as that required a
 +                // diverging expression
 +                // to begin with
 +            },
 +        }
 +        self.maybe_walk_expr(e);
 +    }
 +    fn visit_block(&mut self, _: &'tcx Block<'_>) {
 +        // don't continue over blocks, LateLintPass already does that
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Walks up the AST from the given write expression (`vis.write_expr`) looking
 +/// for reads to the same variable that are unsequenced relative to the write.
 +///
 +/// This means reads for which there is a common ancestor between the read and
 +/// the write such that
 +///
 +/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
 +///   and `|| x = 1` don't necessarily evaluate `x`), and
 +///
 +/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
 +///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
 +///   evaluation order.
 +///
 +/// When such a read is found, the lint is triggered.
 +fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
 +    let map = &vis.cx.tcx.hir();
 +    let mut cur_id = vis.write_expr.hir_id;
 +    loop {
 +        let parent_id = map.get_parent_node(cur_id);
 +        if parent_id == cur_id {
 +            break;
 +        }
 +        let parent_node = match map.find(parent_id) {
 +            Some(parent) => parent,
 +            None => break,
 +        };
 +
 +        let stop_early = match parent_node {
 +            Node::Expr(expr) => check_expr(vis, expr),
 +            Node::Stmt(stmt) => check_stmt(vis, stmt),
 +            Node::Item(_) => {
 +                // We reached the top of the function, stop.
 +                break;
 +            },
 +            _ => StopEarly::KeepGoing,
 +        };
 +        match stop_early {
 +            StopEarly::Stop => break,
 +            StopEarly::KeepGoing => {},
 +        }
 +
 +        cur_id = parent_id;
 +    }
 +}
 +
 +/// Whether to stop early for the loop in `check_for_unsequenced_reads`. (If
 +/// `check_expr` weren't an independent function, this would be unnecessary and
 +/// we could just use `break`).
 +enum StopEarly {
 +    KeepGoing,
 +    Stop,
 +}
 +
 +fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
 +    if expr.hir_id == vis.last_expr.hir_id {
 +        return StopEarly::KeepGoing;
 +    }
 +
 +    match expr.kind {
 +        ExprKind::Array(_)
 +        | ExprKind::Tup(_)
 +        | ExprKind::MethodCall(..)
 +        | ExprKind::Call(_, _)
 +        | ExprKind::Assign(..)
 +        | ExprKind::Index(_, _)
 +        | ExprKind::Repeat(_, _)
 +        | ExprKind::Struct(_, _, _) => {
 +            walk_expr(vis, expr);
 +        },
 +        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
 +            if op.node == BinOpKind::And || op.node == BinOpKind::Or {
 +                // x && y and x || y always evaluate x first, so these are
 +                // strictly sequenced.
 +            } else {
 +                walk_expr(vis, expr);
 +            }
 +        },
 +        ExprKind::Closure(_, _, _, _, _) => {
 +            // Either
 +            //
 +            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
 +            //   function and can stop, or
 +            //
 +            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
 +            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
 +            //   positives.
 +            //
 +            // This is also the only place we need to stop early (grrr).
 +            return StopEarly::Stop;
 +        },
 +        // All other expressions either have only one child or strictly
 +        // sequence the evaluation order of their sub-expressions.
 +        _ => {},
 +    }
 +
 +    vis.last_expr = expr;
 +
 +    StopEarly::KeepGoing
 +}
 +
 +fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
 +    match stmt.kind {
 +        StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
 +        // If the declaration is of a local variable, check its initializer
 +        // expression if it has one. Otherwise, keep going.
 +        StmtKind::Local(local) => local
 +            .init
 +            .as_ref()
 +            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
 +        StmtKind::Item(..) => StopEarly::KeepGoing,
 +    }
 +}
 +
 +/// A visitor that looks for reads from a variable.
 +struct ReadVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    /// The ID of the variable we're looking for.
 +    var: HirId,
 +    /// The expressions where the write to the variable occurred (for reporting
 +    /// in the lint).
 +    write_expr: &'tcx Expr<'tcx>,
 +    /// The last (highest in the AST) expression we've checked, so we know not
 +    /// to recheck it.
 +    last_expr: &'tcx Expr<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if expr.hir_id == self.last_expr.hir_id {
 +            return;
 +        }
 +
 +        if path_to_local_id(expr, self.var) {
 +            // Check that this is a read, not a write.
 +            if !is_in_assignment_position(self.cx, expr) {
 +                span_lint_and_note(
 +                    self.cx,
 +                    EVAL_ORDER_DEPENDENCE,
 +                    expr.span,
 +                    &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
 +                    Some(self.write_expr.span),
 +                    "whether read occurs before this write depends on evaluation order",
 +                );
 +            }
 +        }
 +        match expr.kind {
 +            // We're about to descend a closure. Since we don't know when (or
 +            // if) the closure will be evaluated, any reads in it might not
 +            // occur here (or ever). Like above, bail to avoid false positives.
 +            ExprKind::Closure(_, _, _, _, _) |
 +
 +            // We want to avoid a false positive when a variable name occurs
 +            // only to have its address taken, so we stop here. Technically,
 +            // this misses some weird cases, eg.
 +            //
 +            // ```rust
 +            // let mut x = 0;
 +            // let a = foo(&{x = 1; x}, x);
 +            // ```
 +            //
 +            // TODO: fix this
 +            ExprKind::AddrOf(_, _, _) => {
 +                return;
 +            }
 +            _ => {}
 +        }
 +
 +        walk_expr(self, expr);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
 +fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let Some(parent) = get_parent_expr(cx, expr) {
 +        if let ExprKind::Assign(lhs, ..) = parent.kind {
 +            return lhs.hir_id == expr.hir_id;
 +        }
 +    }
 +    false
 +}
index 129a8475e1c2321dabfb547b91fe9a1151eb34bd,0000000000000000000000000000000000000000..8df7f91ce59f50fe6f7a7ca3bfe7b1762978572e
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,152 @@@
-         if t.ident.name.as_str() == "Display";
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher::FormatExpn;
 +use clippy_utils::last_path_segment;
 +use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 +use clippy_utils::sugg::Sugg;
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BorrowKind, Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::kw;
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `format!("string literal with no
 +    /// argument")` and `format!("{}", foo)` where `foo` is a string.
 +    ///
 +    /// ### Why is this bad?
 +    /// There is no point of doing that. `format!("foo")` can
 +    /// be replaced by `"foo".to_owned()` if you really need a `String`. The even
 +    /// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
 +    /// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
 +    /// if `foo: &str`.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    ///
 +    /// // Bad
 +    /// let foo = "foo";
 +    /// format!("{}", foo);
 +    ///
 +    /// // Good
 +    /// foo.to_owned();
 +    /// ```
 +    pub USELESS_FORMAT,
 +    complexity,
 +    "useless use of `format!`"
 +}
 +
 +declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UselessFormat {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) {
 +            Some(e) if !e.call_site.from_expansion() => e,
 +            _ => return,
 +        };
 +
 +        let mut applicability = Applicability::MachineApplicable;
 +        if format_args.value_args.is_empty() {
 +            if_chain! {
 +                if let [e] = &*format_args.format_string_parts;
 +                if let ExprKind::Lit(lit) = &e.kind;
 +                if let Some(s_src) = snippet_opt(cx, lit.span);
 +                then {
 +                    // Simulate macro expansion, converting {{ and }} to { and }.
 +                    let s_expand = s_src.replace("{{", "{").replace("}}", "}");
 +                    let sugg = format!("{}.to_string()", s_expand);
 +                    span_useless_format(cx, call_site, sugg, applicability);
 +                }
 +            }
 +        } else if let [value] = *format_args.value_args {
 +            if_chain! {
 +                if format_args.format_string_symbols == [kw::Empty];
 +                if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
 +                    ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
 +                    ty::Str => true,
 +                    _ => false,
 +                };
 +                if format_args.args.iter().all(is_display_arg);
 +                if format_args.fmt_expr.map_or(true, check_unformatted);
 +                then {
 +                    let is_new_string = match value.kind {
 +                        ExprKind::Binary(..) => true,
 +                        ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string",
 +                        _ => false,
 +                    };
 +                    let sugg = if is_new_string {
 +                        snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
 +                    } else {
 +                        let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);
 +                        format!("{}.to_string()", sugg.maybe_par())
 +                    };
 +                    span_useless_format(cx, call_site, sugg, applicability);
 +                }
 +            }
 +        };
 +    }
 +}
 +
 +fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut applicability: Applicability) {
 +    // The callsite span contains the statement semicolon for some reason.
 +    if snippet_with_applicability(cx, span, "..", &mut applicability).ends_with(';') {
 +        sugg.push(';');
 +    }
 +
 +    span_lint_and_sugg(
 +        cx,
 +        USELESS_FORMAT,
 +        span,
 +        "useless use of `format!`",
 +        "consider using `.to_string()`",
 +        sugg,
 +        applicability,
 +    );
 +}
 +
 +fn is_display_arg(expr: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let ExprKind::Call(_, [_, fmt]) = expr.kind;
 +        if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind;
 +        if let [.., t, _] = path.segments;
++        if t.ident.name == sym::Display;
 +        then { true } else { false }
 +    }
 +}
 +
 +/// Checks if the expression matches
 +/// ```rust,ignore
 +/// &[_ {
 +///    format: _ {
 +///         width: _::Implied,
 +///         precision: _::Implied,
 +///         ...
 +///    },
 +///    ...,
 +/// }]
 +/// ```
 +fn check_unformatted(expr: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
 +        if let ExprKind::Array([expr]) = expr.kind;
 +        // struct `core::fmt::rt::v1::Argument`
 +        if let ExprKind::Struct(_, fields, _) = expr.kind;
 +        if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
 +        // struct `core::fmt::rt::v1::FormatSpec`
 +        if let ExprKind::Struct(_, fields, _) = format_field.expr.kind;
 +        if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
 +        if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
 +        if last_path_segment(precision_path).ident.name == sym::Implied;
 +        if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width);
 +        if let ExprKind::Path(ref width_qpath) = width_field.expr.kind;
 +        if last_path_segment(width_qpath).ident.name == sym::Implied;
 +        then {
 +            return true;
 +        }
 +    }
 +
 +    false
 +}
index 5feb0ce8dece725d4c902674b8b39e049939d1fb,0000000000000000000000000000000000000000..73bdd67ff5d25a864b88c23055d7e8cec1b63c18
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,94 @@@
- use if_chain::if_chain;
 +use clippy_utils::source::snippet;
-     if_chain! {
-         if let BinOpKind::Shl = cmp.node;
-         if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), right);
-         if let Some(Constant::Int(1)) = constant_simple(cx, cx.typeck_results(), left);
-         then {
-             return true;
-         }
-     }
-     false
 +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::{clip, unsext};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for identity operations, e.g., `x + 0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This code can be removed without changing the
 +    /// meaning. So it just obscures what's going on. Delete it mercilessly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// x / 1 + 0 * 1 - 0 | 0;
 +    /// ```
 +    pub IDENTITY_OP,
 +    complexity,
 +    "using identity operations, e.g., `x + 0` or `y / 1`"
 +}
 +
 +declare_lint_pass!(IdentityOp => [IDENTITY_OP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IdentityOp {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::Binary(cmp, left, right) = e.kind {
 +            if is_allowed(cx, cmp, left, right) {
 +                return;
 +            }
 +            match cmp.node {
 +                BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
 +                    check(cx, left, 0, e.span, right.span);
 +                    check(cx, right, 0, e.span, left.span);
 +                },
 +                BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
 +                BinOpKind::Mul => {
 +                    check(cx, left, 1, e.span, right.span);
 +                    check(cx, right, 1, e.span, left.span);
 +                },
 +                BinOpKind::Div => check(cx, right, 1, e.span, left.span),
 +                BinOpKind::BitAnd => {
 +                    check(cx, left, -1, e.span, right.span);
 +                    check(cx, right, -1, e.span, left.span);
 +                },
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
 +    // `1 << 0` is a common pattern in bit manipulation code
++    cmp.node == BinOpKind::Shl
++        && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
++        && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
 +}
 +
 +#[allow(clippy::cast_possible_wrap)]
 +fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
 +    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
 +        let check = match *cx.typeck_results().expr_ty(e).kind() {
 +            ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
 +            ty::Uint(uty) => clip(cx.tcx, !0, uty),
 +            _ => return,
 +        };
 +        if match m {
 +            0 => v == 0,
 +            -1 => v == check,
 +            1 => v == 1,
 +            _ => unreachable!(),
 +        } {
 +            span_lint(
 +                cx,
 +                IDENTITY_OP,
 +                span,
 +                &format!(
 +                    "the operation is ineffective. Consider reducing it to `{}`",
 +                    snippet(cx, arg, "..")
 +                ),
 +            );
 +        }
 +    }
 +}
index ee575c81a8b0b69061110b696db5fc9399c85de2,0000000000000000000000000000000000000000..10bca59e6d06ab5da76ebe19bbba10020f50f9a8
mode 100644,000000..100644
--- /dev/null
@@@ -1,97 -1,0 +1,99 @@@
- use clippy_utils::is_expn_of;
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher::PanicExpn;
-                 let cond_sugg =
-                 if let ExprKind::DropTemps(Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..}) = cond.kind {
-                     snippet_with_applicability(cx, not_expr.span, "..", &mut applicability).to_string()
 +use clippy_utils::source::snippet_with_applicability;
++use clippy_utils::{is_expn_of, sugg};
 +use rustc_errors::Applicability;
 +use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `assert!` is simpler than `if`-then-`panic!`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let sad_people: Vec<&str> = vec![];
 +    /// if !sad_people.is_empty() {
 +    ///     panic!("there are sad people: {:?}", sad_people);
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let sad_people: Vec<&str> = vec![];
 +    /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
 +    /// ```
 +    pub IF_THEN_PANIC,
 +    style,
 +    "`panic!` and only a `panic!` in `if`-then statement"
 +}
 +
 +declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
 +
 +impl LateLintPass<'_> for IfThenPanic {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let Expr {
 +                kind: ExprKind:: If(cond, Expr {
 +                    kind: ExprKind::Block(
 +                        Block {
 +                            stmts: [stmt],
 +                            ..
 +                        },
 +                        _),
 +                    ..
 +                }, None),
 +                ..
 +            } = &expr;
 +            if is_expn_of(stmt.span, "panic").is_some();
 +            if !matches!(cond.kind, ExprKind::Let(_, _, _));
 +            if let StmtKind::Semi(semi) = stmt.kind;
 +            if !cx.tcx.sess.source_map().is_multiline(cond.span);
 +
 +            then {
 +                let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
 +                    match *panic_expn.format_args.value_args {
 +                        [] => panic_expn.format_args.format_string_span,
 +                        [.., last] => panic_expn.format_args.format_string_span.to(last.span),
 +                    }
 +                } else {
 +                    if_chain! {
 +                        if let ExprKind::Block(block, _) = semi.kind;
 +                        if let Some(init) = block.expr;
 +                        if let ExprKind::Call(_, [format_args]) = init.kind;
 +
 +                        then {
 +                            format_args.span
 +                        } else {
 +                            return
 +                        }
 +                    }
 +                };
 +                let mut applicability = Applicability::MachineApplicable;
 +                let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
-                     format!("!{}", snippet_with_applicability(cx, cond.span, "..", &mut applicability))
++                let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
++                    if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
++                         sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
++                    } else {
++                       format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par().to_string())
++                    }
 +                } else {
++                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string())
 +                };
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    IF_THEN_PANIC,
 +                    expr.span,
 +                    "only a `panic!` in `if`-then statement",
 +                    "try",
 +                    format!("assert!({}, {});", cond_sugg, sugg),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
index 9da06d1418e2deafe82aa7d7ccb72bd9118b3788,0000000000000000000000000000000000000000..81eb51e6f7cee304c034b367544f32eaa0268846
mode 100644,000000..100644
--- /dev/null
@@@ -1,386 -1,0 +1,394 @@@
-                             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");
 +use std::borrow::Cow;
 +use std::collections::BTreeMap;
 +
 +use rustc_errors::DiagnosticBuilder;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, NestedVisitorMap, Visitor};
 +use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, 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::{Ty, TyS, TypeckResults};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::sym;
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use if_chain::if_chain;
 +
 +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 +use clippy_utils::differing_macro_contexts;
 +use clippy_utils::source::{snippet, snippet_opt};
 +use clippy_utils::ty::is_type_diagnostic_item;
 +
 +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.def_id) {
 +            return;
 +        }
 +
 +        match item.kind {
 +            ItemKind::Impl(ref impl_) => {
 +                let mut vis = ImplicitHasherTypeVisitor::new(cx);
 +                vis.visit_ty(impl_.self_ty);
 +
 +                for target in &vis.found {
 +                    if differing_macro_contexts(item.span, target.span()) {
 +                        return;
 +                    }
 +
 +                    let generics_suggestion_span = impl_.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.ctxt(), item.span.parent())
 +                        } else {
 +                            return;
 +                        }
 +                    });
 +
 +                    let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
 +                    for item in impl_.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, impl_.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,
++                                Span::new(
++                                    item.span.lo(),
++                                    body.params[0].pat.span.lo(),
++                                    item.span.ctxt(),
++                                    item.span.parent(),
++                                ),
++                            )
++                            .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.ctxt(), item.span.parent())
 +                        });
 +
 +                        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, 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) && 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) && 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 visit_infer(&mut self, inf: &'tcx hir::InferArg) {
 +        if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) {
 +            self.found.push(target);
 +        }
 +
 +        walk_inf(self, inf);
 +    }
 +
 +    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(fun, args) = e.kind;
 +            if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind;
 +            if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
 +            if let Some(ty_did) = ty_path.res.opt_def_id();
 +            then {
 +                if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
 +                    return;
 +                }
 +
 +                if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
 +                    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 self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
 +                    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())
 +    }
 +}
index a0e6f12b8122e1b45e2b3e0deae10af5db9c0759,0000000000000000000000000000000000000000..c962e814fa5c2eb33af2e3d110857afe409f3bea
mode 100644,000000..100644
--- /dev/null
@@@ -1,59 -1,0 +1,59 @@@
-         if let hir::BinOpKind::Div = &binop.node;
 +use clippy_utils::diagnostics::span_lint_and_help;
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for division of integers
 +    ///
 +    /// ### Why is this bad?
 +    /// When outside of some very specific algorithms,
 +    /// integer division is very often a mistake because it discards the
 +    /// remainder.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let x = 3 / 2;
 +    /// println!("{}", x);
 +    ///
 +    /// // Good
 +    /// let x = 3f32 / 2f32;
 +    /// println!("{}", x);
 +    /// ```
 +    pub INTEGER_DIVISION,
 +    restriction,
 +    "integer division may cause loss of precision"
 +}
 +
 +declare_lint_pass!(IntegerDivision => [INTEGER_DIVISION]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IntegerDivision {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_integer_division(cx, expr) {
 +            span_lint_and_help(
 +                cx,
 +                INTEGER_DIVISION,
 +                expr.span,
 +                "integer division",
 +                None,
 +                "division of integers may cause loss of precision. consider using floats",
 +            );
 +        }
 +    }
 +}
 +
 +fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool {
 +    if_chain! {
 +        if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
++        if binop.node == hir::BinOpKind::Div;
 +        then {
 +            let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right));
 +            return left_ty.is_integral() && right_ty.is_integral();
 +        }
 +    }
 +
 +    false
 +}
index e4b8e7546283b460f6f40da388ae8b3c51453d3c,0000000000000000000000000000000000000000..392166237be50eb8fd785afd57902d58c0874c24
mode 100644,000000..100644
--- /dev/null
@@@ -1,140 -1,0 +1,175 @@@
- use clippy_utils::source::snippet_opt;
 +//! lint when there is a large size difference between variants on an enum
 +
 +use clippy_utils::diagnostics::span_lint_and_then;
- use rustc_hir::{Item, ItemKind, VariantData};
++use clippy_utils::source::snippet_with_applicability;
 +use rustc_errors::Applicability;
-             let mut largest_variant: Option<(_, _)> = None;
-             let mut second_variant: Option<(_, _)> = None;
-             for (i, variant) in adt.variants.iter().enumerate() {
-                 let size: u64 = variant
-                     .fields
-                     .iter()
-                     .filter_map(|f| {
-                         let ty = cx.tcx.type_of(f.did);
-                         // don't count generics by filtering out everything
-                         // that does not have a layout
-                         cx.layout_of(ty).ok().map(|l| l.size.bytes())
-                     })
-                     .sum();
-                 let grouped = (size, (i, variant));
-                 if grouped.0 >= largest_variant.map_or(0, |x| x.0) {
-                     second_variant = largest_variant;
-                     largest_variant = Some(grouped);
-                 }
++use rustc_hir::{Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::layout::LayoutOf;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
++use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for large size differences between variants on
 +    /// `enum`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// Enum size is bounded by the largest variant. Having a
 +    /// large variant can penalize the memory layout of that enum.
 +    ///
 +    /// ### Known problems
 +    /// This lint obviously cannot take the distribution of
 +    /// variants in your running program into account. It is possible that the
 +    /// smaller variants make up less than 1% of all instances, in which case
 +    /// the overhead is negligible and the boxing is counter-productive. Always
 +    /// measure the change this lint suggests.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// enum Test {
 +    ///     A(i32),
 +    ///     B([i32; 8000]),
 +    /// }
 +    ///
 +    /// // Possibly better
 +    /// enum Test2 {
 +    ///     A(i32),
 +    ///     B(Box<[i32; 8000]>),
 +    /// }
 +    /// ```
 +    pub LARGE_ENUM_VARIANT,
 +    perf,
 +    "large size difference between variants on an enum"
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct LargeEnumVariant {
 +    maximum_size_difference_allowed: u64,
 +}
 +
 +impl LargeEnumVariant {
 +    #[must_use]
 +    pub fn new(maximum_size_difference_allowed: u64) -> Self {
 +        Self {
 +            maximum_size_difference_allowed,
 +        }
 +    }
 +}
 +
++struct FieldInfo {
++    ind: usize,
++    size: u64,
++}
++
++struct VariantInfo {
++    ind: usize,
++    size: u64,
++    fields_size: Vec<FieldInfo>,
++}
++
 +impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        if in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +        if let ItemKind::Enum(ref def, _) = item.kind {
 +            let ty = cx.tcx.type_of(item.def_id);
 +            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
-             if let (Some(largest), Some(second)) = (largest_variant, second_variant) {
-                 let difference = largest.0 - second.0;
++            if adt.variants.len() <= 1 {
++                return;
 +            }
++            let mut variants_size: Vec<VariantInfo> = adt
++                .variants
++                .iter()
++                .enumerate()
++                .map(|(i, variant)| {
++                    let mut fields_size = Vec::new();
++                    let size: u64 = variant
++                        .fields
++                        .iter()
++                        .enumerate()
++                        .filter_map(|(i, f)| {
++                            let ty = cx.tcx.type_of(f.did);
++                            // don't count generics by filtering out everything
++                            // that does not have a layout
++                            cx.layout_of(ty).ok().map(|l| {
++                                let size = l.size.bytes();
++                                fields_size.push(FieldInfo { ind: i, size });
++                                size
++                            })
++                        })
++                        .sum();
++                    VariantInfo {
++                        ind: i,
++                        size,
++                        fields_size,
++                    }
++                })
++                .collect();
 +
-                 if difference > self.maximum_size_difference_allowed {
-                     let (i, variant) = largest.1;
++            variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
 +
-                     let help_text = "consider boxing the large fields to reduce the total size of the enum";
-                     span_lint_and_then(
-                         cx,
-                         LARGE_ENUM_VARIANT,
-                         def.variants[i].span,
-                         "large size difference between variants",
-                         |diag| {
-                             diag.span_label(
-                                 def.variants[(largest.1).0].span,
-                                 &format!("this variant is {} bytes", largest.0),
-                             );
-                             diag.span_note(
-                                 def.variants[(second.1).0].span,
-                                 &format!("and the second-largest variant is {} bytes:", second.0),
-                             );
-                             if variant.fields.len() == 1 {
-                                 let span = match def.variants[i].data {
-                                     VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) => {
-                                         fields[0].ty.span
-                                     },
-                                     VariantData::Unit(..) => unreachable!(),
-                                 };
-                                 if let Some(snip) = snippet_opt(cx, span) {
-                                     diag.span_suggestion(
-                                         span,
-                                         help_text,
-                                         format!("Box<{}>", snip),
-                                         Applicability::MaybeIncorrect,
-                                     );
-                                     return;
++            let mut difference = variants_size[0].size - variants_size[1].size;
++            if difference > self.maximum_size_difference_allowed {
++                let help_text = "consider boxing the large fields to reduce the total size of the enum";
++                span_lint_and_then(
++                    cx,
++                    LARGE_ENUM_VARIANT,
++                    def.variants[variants_size[0].ind].span,
++                    "large size difference between variants",
++                    |diag| {
++                        diag.span_label(
++                            def.variants[variants_size[0].ind].span,
++                            &format!("this variant is {} bytes", variants_size[0].size),
++                        );
++                        diag.span_note(
++                            def.variants[variants_size[1].ind].span,
++                            &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
++                        );
 +
-                             }
-                             diag.span_help(def.variants[i].span, help_text);
-                         },
-                     );
-                 }
++                        let fields = def.variants[variants_size[0].ind].data.fields();
++                        variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
++                        let mut applicability = Applicability::MaybeIncorrect;
++                        let sugg: Vec<(Span, String)> = variants_size[0]
++                            .fields_size
++                            .iter()
++                            .rev()
++                            .map_while(|val| {
++                                if difference > self.maximum_size_difference_allowed {
++                                    difference = difference.saturating_sub(val.size);
++                                    Some((
++                                        fields[val.ind].ty.span,
++                                        format!(
++                                            "Box<{}>",
++                                            snippet_with_applicability(
++                                                cx,
++                                                fields[val.ind].ty.span,
++                                                "..",
++                                                &mut applicability
++                                            )
++                                            .into_owned()
++                                        ),
++                                    ))
++                                } else {
++                                    None
 +                                }
++                            })
++                            .collect();
++
++                        if !sugg.is_empty() {
++                            diag.multipart_suggestion(help_text, sugg, Applicability::MaybeIncorrect);
++                            return;
++                        }
++
++                        diag.span_help(def.variants[variants_size[0].ind].span, help_text);
++                    },
++                );
 +            }
 +        }
 +    }
 +}
index de46e50a68a137c950a11a3d77b04e898ddd94a0,0000000000000000000000000000000000000000..f336fb9d42f88be86071b100ee85a83e0f6c44f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,494 -1,0 +1,490 @@@
-         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
-             }
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefIdSet;
 +use rustc_hir::{
 +    def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
 +    ItemKind, Mutability, Node, TraitItemRef, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, AssocKind, FnSig, Ty, TyS};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{
 +    source_map::{Span, Spanned, Symbol},
 +    symbol::sym,
 +};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for getting the length of something via `.len()`
 +    /// just to compare to zero, and suggests using `.is_empty()` where applicable.
 +    ///
 +    /// ### Why is this bad?
 +    /// Some structures can answer `.is_empty()` much faster
 +    /// than calculating their length. So it is good to get into the habit of using
 +    /// `.is_empty()`, and having it is cheap.
 +    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// if x.len() == 0 {
 +    ///     ..
 +    /// }
 +    /// if y.len() != 0 {
 +    ///     ..
 +    /// }
 +    /// ```
 +    /// instead use
 +    /// ```ignore
 +    /// if x.is_empty() {
 +    ///     ..
 +    /// }
 +    /// if !y.is_empty() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub LEN_ZERO,
 +    style,
 +    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for items that implement `.len()` but not
 +    /// `.is_empty()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is good custom to have both methods, because for
 +    /// some data structures, asking about the length will be a costly operation,
 +    /// whereas `.is_empty()` can usually answer in constant time. Also it used to
 +    /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
 +    /// lint will ignore such entities.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// impl X {
 +    ///     pub fn len(&self) -> usize {
 +    ///         ..
 +    ///     }
 +    /// }
 +    /// ```
 +    pub LEN_WITHOUT_IS_EMPTY,
 +    style,
 +    "traits or impls with a public `len` method but no corresponding `is_empty` method"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for comparing to an empty slice such as `""` or `[]`,
 +    /// and suggests using `.is_empty()` where applicable.
 +    ///
 +    /// ### Why is this bad?
 +    /// Some structures can answer `.is_empty()` much faster
 +    /// than checking for equality. So it is good to get into the habit of using
 +    /// `.is_empty()`, and having it is cheap.
 +    /// Besides, it makes the intent clearer than a manual comparison in some contexts.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```ignore
 +    /// if s == "" {
 +    ///     ..
 +    /// }
 +    ///
 +    /// if arr == [] {
 +    ///     ..
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```ignore
 +    /// if s.is_empty() {
 +    ///     ..
 +    /// }
 +    ///
 +    /// if arr.is_empty() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub COMPARISON_TO_EMPTY,
 +    style,
 +    "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
 +}
 +
 +declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LenZero {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if item.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
 +            check_trait_items(cx, item, trait_items);
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if_chain! {
 +            if item.ident.name == sym::len;
 +            if let ImplItemKind::Fn(sig, _) = &item.kind;
 +            if sig.decl.implicit_self.has_implicit_self();
 +            if cx.access_levels.is_exported(item.def_id);
 +            if matches!(sig.decl.output, FnRetTy::Return(_));
 +            if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
 +            if imp.of_trait.is_none();
 +            if let TyKind::Path(ty_path) = &imp.self_ty.kind;
 +            if let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id();
 +            if let Some(local_id) = ty_id.as_local();
 +            let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
 +            if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
 +            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.def_id).skip_binder());
 +            then {
 +                let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
 +                    Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
 +                    Some(Node::Item(x)) => match x.kind {
 +                        ItemKind::Struct(..) => (x.ident.name, "struct"),
 +                        ItemKind::Enum(..) => (x.ident.name, "enum"),
 +                        ItemKind::Union(..) => (x.ident.name, "union"),
 +                        _ => (x.ident.name, "type"),
 +                    }
 +                    _ => return,
 +                };
 +                check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind)
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
 +            match cmp {
 +                BinOpKind::Eq => {
 +                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
 +                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
 +                },
 +                BinOpKind::Ne => {
 +                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
 +                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
 +                },
 +                BinOpKind::Gt => {
 +                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
 +                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
 +                },
 +                BinOpKind::Lt => {
 +                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
 +                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
 +                },
 +                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
 +                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
 +    fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
 +        item.ident.name == name
 +            && if let AssocItemKind::Fn { has_self } = item.kind {
 +                has_self && { cx.tcx.fn_sig(item.id.def_id).inputs().skip_binder().len() == 1 }
 +            } else {
 +                false
 +            }
 +    }
 +
 +    // fill the set with current and super traits
 +    fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
 +        if set.insert(traitt) {
 +            for supertrait in rustc_trait_selection::traits::supertrait_def_ids(cx.tcx, traitt) {
 +                fill_trait_set(supertrait, set, cx);
 +            }
 +        }
 +    }
 +
 +    if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
 +    {
 +        let mut current_and_super_traits = DefIdSet::default();
 +        fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
 +
 +        let is_empty_method_found = current_and_super_traits
 +            .iter()
 +            .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
 +            .any(|i| {
 +                i.kind == ty::AssocKind::Fn
 +                    && i.fn_has_self_parameter
 +                    && i.ident.name == sym!(is_empty)
 +                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
 +            });
 +
 +        if !is_empty_method_found {
 +            span_lint(
 +                cx,
 +                LEN_WITHOUT_IS_EMPTY,
 +                visited_trait.span,
 +                &format!(
 +                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
 +                    visited_trait.ident.name
 +                ),
 +            );
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Copy)]
 +enum LenOutput<'tcx> {
 +    Integral,
 +    Option(DefId),
 +    Result(DefId, Ty<'tcx>),
 +}
 +fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
 +    match *sig.output().kind() {
 +        ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
 +        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
 +            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did))
 +        },
 +        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did) => subs
 +            .type_at(0)
 +            .is_integral()
 +            .then(|| LenOutput::Result(adt.did, subs.type_at(1))),
 +        _ => None,
 +    }
 +}
 +
 +impl LenOutput<'_> {
 +    fn matches_is_empty_output(self, ty: Ty<'_>) -> bool {
 +        match (self, ty.kind()) {
 +            (_, &ty::Bool) => true,
 +            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did => subs.type_at(0).is_bool(),
 +            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did => {
 +                subs.type_at(0).is_bool() && TyS::same_type(subs.type_at(1), err_ty)
 +            },
 +            _ => false,
 +        }
 +    }
 +
 +    fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
 +        let self_ref = match self_kind {
 +            ImplicitSelfKind::ImmRef => "&",
 +            ImplicitSelfKind::MutRef => "&mut ",
 +            _ => "",
 +        };
 +        match self {
 +            Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref),
 +            Self::Option(_) => format!(
 +                "expected signature: `({}self) -> bool` or `({}self) -> Option<bool>",
 +                self_ref, self_ref
 +            ),
 +            Self::Result(..) => format!(
 +                "expected signature: `({}self) -> bool` or `({}self) -> Result<bool>",
 +                self_ref, self_ref
 +            ),
 +        }
 +    }
 +}
 +
 +/// Checks if the given signature matches the expectations for `is_empty`
 +fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> bool {
 +    match &**sig.inputs_and_output {
 +        [arg, res] if len_output.matches_is_empty_output(res) => {
 +            matches!(
 +                (arg.kind(), self_kind),
 +                (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
 +                    | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef)
 +            ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the given type has an `is_empty` method with the appropriate signature.
 +fn check_for_is_empty(
 +    cx: &LateContext<'_>,
 +    span: Span,
 +    self_kind: ImplicitSelfKind,
 +    output: LenOutput<'_>,
 +    impl_ty: DefId,
 +    item_name: Symbol,
 +    item_kind: &str,
 +) {
 +    let is_empty = Symbol::intern("is_empty");
 +    let is_empty = cx
 +        .tcx
 +        .inherent_impls(impl_ty)
 +        .iter()
 +        .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
 +        .find(|item| item.kind == AssocKind::Fn);
 +
 +    let (msg, is_empty_span, self_kind) = match is_empty {
 +        None => (
 +            format!(
 +                "{} `{}` has a public `len` method, but no `is_empty` method",
 +                item_kind,
 +                item_name.as_str(),
 +            ),
 +            None,
 +            None,
 +        ),
 +        Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
 +            format!(
 +                "{} `{}` has a public `len` method, but a private `is_empty` method",
 +                item_kind,
 +                item_name.as_str(),
 +            ),
 +            Some(cx.tcx.def_span(is_empty.def_id)),
 +            None,
 +        ),
 +        Some(is_empty)
 +            if !(is_empty.fn_has_self_parameter
 +                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
 +        {
 +            (
 +                format!(
 +                    "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
 +                    item_kind,
 +                    item_name.as_str(),
 +                ),
 +                Some(cx.tcx.def_span(is_empty.def_id)),
 +                Some(self_kind),
 +            )
 +        },
 +        Some(_) => return,
 +    };
 +
 +    span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, &msg, |db| {
 +        if let Some(span) = is_empty_span {
 +            db.span_note(span, "`is_empty` defined here");
 +        }
 +        if let Some(self_kind) = self_kind {
 +            db.note(&output.expected_sig(self_kind));
 +        }
 +    });
 +}
 +
 +fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
 +    if let (&ExprKind::MethodCall(method_path, _, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
 +        // check if we are in an is_empty() method
 +        if let Some(name) = get_item_name(cx, method) {
 +            if name.as_str() == "is_empty" {
 +                return;
 +            }
 +        }
 +
 +        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
 +    } else {
 +        check_empty_expr(cx, span, method, lit, op);
 +    }
 +}
 +
 +fn check_len(
 +    cx: &LateContext<'_>,
 +    span: Span,
 +    method_name: Symbol,
 +    args: &[Expr<'_>],
 +    lit: &LitKind,
 +    op: &str,
 +    compare_to: u32,
 +) {
 +    if let LitKind::Int(lit, _) = *lit {
 +        // check if length is compared to the specified number
 +        if lit != u128::from(compare_to) {
 +            return;
 +        }
 +
 +        if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                LEN_ZERO,
 +                span,
 +                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
 +                &format!("using `{}is_empty` is clearer and more explicit", op),
 +                format!(
 +                    "{}{}.is_empty()",
 +                    op,
 +                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
 +                ),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
 +    if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
 +        let mut applicability = Applicability::MachineApplicable;
 +        span_lint_and_sugg(
 +            cx,
 +            COMPARISON_TO_EMPTY,
 +            span,
 +            "comparison to empty slice",
 +            &format!("using `{}is_empty` is clearer and more explicit", op),
 +            format!(
 +                "{}{}.is_empty()",
 +                op,
 +                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
 +            ),
 +            applicability,
 +        );
 +    }
 +}
 +
 +fn is_empty_string(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Lit(ref lit) = expr.kind {
 +        if let LitKind::Str(lit, _) = lit.node {
 +            let lit = lit.as_str();
 +            return lit == "";
 +        }
 +    }
 +    false
 +}
 +
 +fn is_empty_array(expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Array(arr) = expr.kind {
 +        return arr.is_empty();
 +    }
 +    false
 +}
 +
 +/// Checks if this type has an `is_empty` method.
 +fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
 +    fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
++        if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" {
++            let sig = cx.tcx.fn_sig(item.def_id);
++            let ty = sig.skip_binder();
++            ty.inputs().len() == 1
 +        } else {
 +            false
 +        }
 +    }
 +
 +    /// Checks the inherent impl's items for an `is_empty(self)` method.
 +    fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
 +        cx.tcx.inherent_impls(id).iter().any(|imp| {
 +            cx.tcx
 +                .associated_items(*imp)
 +                .in_definition_order()
 +                .any(|item| is_is_empty(cx, item))
 +        })
 +    }
 +
 +    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
 +    match ty.kind() {
 +        ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
 +            cx.tcx
 +                .associated_items(principal.def_id())
 +                .in_definition_order()
 +                .any(|item| is_is_empty(cx, item))
 +        }),
 +        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
 +        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
 +        ty::Array(..) | ty::Slice(..) | ty::Str => true,
 +        _ => false,
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..80bde1b11384bcdac112af06f27f88b63526dadb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,70 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++{
++    store.register_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::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::unused_collect",
++        "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
++    );
++    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",
++    );
++    store.register_removed(
++        "clippy::find_map",
++        "this lint has been replaced by `manual_find_map`, a more specific lint",
++    );
++    store.register_removed(
++        "clippy::filter_map",
++        "this lint has been replaced by `manual_filter_map`, a more specific lint",
++    );
++    store.register_removed(
++        "clippy::pub_enum_variant_names",
++        "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items",
++    );
++    store.register_removed(
++        "clippy::wrong_pub_self_convention",
++        "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items",
++    );
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e6e0244754fbc36de70b56eaba31e16ea363cc8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,304 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::all", Some("clippy_all"), vec![
++    LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
++    LintId::of(approx_const::APPROX_CONSTANT),
++    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
++    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
++    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
++    LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
++    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
++    LintId::of(attrs::DEPRECATED_CFG_ATTR),
++    LintId::of(attrs::DEPRECATED_SEMVER),
++    LintId::of(attrs::MISMATCHED_TARGET_OS),
++    LintId::of(attrs::USELESS_ATTRIBUTE),
++    LintId::of(bit_mask::BAD_BIT_MASK),
++    LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
++    LintId::of(blacklisted_name::BLACKLISTED_NAME),
++    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
++    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
++    LintId::of(booleans::LOGIC_BUG),
++    LintId::of(booleans::NONMINIMAL_BOOL),
++    LintId::of(casts::CAST_REF_TO_MUT),
++    LintId::of(casts::CHAR_LIT_AS_U8),
++    LintId::of(casts::FN_TO_NUMERIC_CAST),
++    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
++    LintId::of(casts::UNNECESSARY_CAST),
++    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
++    LintId::of(collapsible_if::COLLAPSIBLE_IF),
++    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
++    LintId::of(comparison_chain::COMPARISON_CHAIN),
++    LintId::of(copies::IFS_SAME_COND),
++    LintId::of(copies::IF_SAME_THEN_ELSE),
++    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
++    LintId::of(derivable_impls::DERIVABLE_IMPLS),
++    LintId::of(derive::DERIVE_HASH_XOR_EQ),
++    LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
++    LintId::of(doc::MISSING_SAFETY_DOC),
++    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
++    LintId::of(double_comparison::DOUBLE_COMPARISONS),
++    LintId::of(double_parens::DOUBLE_PARENS),
++    LintId::of(drop_forget_ref::DROP_COPY),
++    LintId::of(drop_forget_ref::DROP_REF),
++    LintId::of(drop_forget_ref::FORGET_COPY),
++    LintId::of(drop_forget_ref::FORGET_REF),
++    LintId::of(duration_subsec::DURATION_SUBSEC),
++    LintId::of(entry::MAP_ENTRY),
++    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
++    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
++    LintId::of(enum_variants::MODULE_INCEPTION),
++    LintId::of(eq_op::EQ_OP),
++    LintId::of(eq_op::OP_REF),
++    LintId::of(erasing_op::ERASING_OP),
++    LintId::of(escape::BOXED_LOCAL),
++    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
++    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
++    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
++    LintId::of(explicit_write::EXPLICIT_WRITE),
++    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
++    LintId::of(float_literal::EXCESSIVE_PRECISION),
++    LintId::of(format::USELESS_FORMAT),
++    LintId::of(formatting::POSSIBLE_MISSING_COMMA),
++    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
++    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
++    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
++    LintId::of(from_over_into::FROM_OVER_INTO),
++    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
++    LintId::of(functions::DOUBLE_MUST_USE),
++    LintId::of(functions::MUST_USE_UNIT),
++    LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
++    LintId::of(functions::RESULT_UNIT_ERR),
++    LintId::of(functions::TOO_MANY_ARGUMENTS),
++    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
++    LintId::of(identity_op::IDENTITY_OP),
++    LintId::of(if_let_mutex::IF_LET_MUTEX),
++    LintId::of(if_then_panic::IF_THEN_PANIC),
++    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::COMPARISON_TO_EMPTY),
++    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
++    LintId::of(len_zero::LEN_ZERO),
++    LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
++    LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
++    LintId::of(lifetimes::NEEDLESS_LIFETIMES),
++    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
++    LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
++    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
++    LintId::of(loops::EMPTY_LOOP),
++    LintId::of(loops::EXPLICIT_COUNTER_LOOP),
++    LintId::of(loops::FOR_KV_MAP),
++    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
++    LintId::of(loops::ITER_NEXT_LOOP),
++    LintId::of(loops::MANUAL_FLATTEN),
++    LintId::of(loops::MANUAL_MEMCPY),
++    LintId::of(loops::MUT_RANGE_BOUND),
++    LintId::of(loops::NEEDLESS_COLLECT),
++    LintId::of(loops::NEEDLESS_RANGE_LOOP),
++    LintId::of(loops::NEVER_LOOP),
++    LintId::of(loops::SAME_ITEM_PUSH),
++    LintId::of(loops::SINGLE_ELEMENT_LOOP),
++    LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
++    LintId::of(loops::WHILE_LET_LOOP),
++    LintId::of(loops::WHILE_LET_ON_ITERATOR),
++    LintId::of(main_recursion::MAIN_RECURSION),
++    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
++    LintId::of(manual_map::MANUAL_MAP),
++    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
++    LintId::of(manual_strip::MANUAL_STRIP),
++    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
++    LintId::of(map_clone::MAP_CLONE),
++    LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
++    LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
++    LintId::of(match_result_ok::MATCH_RESULT_OK),
++    LintId::of(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::BYTES_NTH),
++    LintId::of(methods::CHARS_LAST_CMP),
++    LintId::of(methods::CHARS_NEXT_CMP),
++    LintId::of(methods::CLONE_DOUBLE_REF),
++    LintId::of(methods::CLONE_ON_COPY),
++    LintId::of(methods::EXPECT_FUN_CALL),
++    LintId::of(methods::EXTEND_WITH_DRAIN),
++    LintId::of(methods::FILTER_MAP_IDENTITY),
++    LintId::of(methods::FILTER_NEXT),
++    LintId::of(methods::FLAT_MAP_IDENTITY),
++    LintId::of(methods::INSPECT_FOR_EACH),
++    LintId::of(methods::INTO_ITER_ON_REF),
++    LintId::of(methods::ITERATOR_STEP_BY_ZERO),
++    LintId::of(methods::ITER_CLONED_COLLECT),
++    LintId::of(methods::ITER_COUNT),
++    LintId::of(methods::ITER_NEXT_SLICE),
++    LintId::of(methods::ITER_NTH),
++    LintId::of(methods::ITER_NTH_ZERO),
++    LintId::of(methods::ITER_SKIP_NEXT),
++    LintId::of(methods::MANUAL_FILTER_MAP),
++    LintId::of(methods::MANUAL_FIND_MAP),
++    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
++    LintId::of(methods::MANUAL_SPLIT_ONCE),
++    LintId::of(methods::MANUAL_STR_REPEAT),
++    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
++    LintId::of(methods::MAP_IDENTITY),
++    LintId::of(methods::NEW_RET_NO_SELF),
++    LintId::of(methods::OK_EXPECT),
++    LintId::of(methods::OPTION_AS_REF_DEREF),
++    LintId::of(methods::OPTION_FILTER_MAP),
++    LintId::of(methods::OPTION_MAP_OR_NONE),
++    LintId::of(methods::OR_FUN_CALL),
++    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
++    LintId::of(methods::SEARCH_IS_SOME),
++    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
++    LintId::of(methods::SINGLE_CHAR_ADD_STR),
++    LintId::of(methods::SINGLE_CHAR_PATTERN),
++    LintId::of(methods::SKIP_WHILE_NEXT),
++    LintId::of(methods::STRING_EXTEND_CHARS),
++    LintId::of(methods::SUSPICIOUS_MAP),
++    LintId::of(methods::SUSPICIOUS_SPLITN),
++    LintId::of(methods::UNINIT_ASSUMED_INIT),
++    LintId::of(methods::UNNECESSARY_FILTER_MAP),
++    LintId::of(methods::UNNECESSARY_FOLD),
++    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
++    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
++    LintId::of(methods::USELESS_ASREF),
++    LintId::of(methods::WRONG_SELF_CONVENTION),
++    LintId::of(methods::ZST_OFFSET),
++    LintId::of(minmax::MIN_MAX),
++    LintId::of(misc::CMP_NAN),
++    LintId::of(misc::CMP_OWNED),
++    LintId::of(misc::MODULO_ONE),
++    LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
++    LintId::of(misc::TOPLEVEL_REF_ARG),
++    LintId::of(misc::ZERO_PTR),
++    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
++    LintId::of(misc_early::DOUBLE_NEG),
++    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
++    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
++    LintId::of(misc_early::REDUNDANT_PATTERN),
++    LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
++    LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
++    LintId::of(mut_key::MUTABLE_KEY_TYPE),
++    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
++    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
++    LintId::of(mutex_atomic::MUTEX_ATOMIC),
++    LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
++    LintId::of(needless_bool::BOOL_COMPARISON),
++    LintId::of(needless_bool::NEEDLESS_BOOL),
++    LintId::of(needless_borrow::NEEDLESS_BORROW),
++    LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
++    LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
++    LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
++    LintId::of(needless_update::NEEDLESS_UPDATE),
++    LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
++    LintId::of(neg_multiply::NEG_MULTIPLY),
++    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
++    LintId::of(no_effect::NO_EFFECT),
++    LintId::of(no_effect::UNNECESSARY_OPERATION),
++    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
++    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
++    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
++    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
++    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
++    LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
++    LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
++    LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
++    LintId::of(precedence::PRECEDENCE),
++    LintId::of(ptr::CMP_NULL),
++    LintId::of(ptr::INVALID_NULL_PTR_USAGE),
++    LintId::of(ptr::MUT_FROM_REF),
++    LintId::of(ptr::PTR_ARG),
++    LintId::of(ptr_eq::PTR_EQ),
++    LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
++    LintId::of(question_mark::QUESTION_MARK),
++    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
++    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
++    LintId::of(ranges::REVERSED_EMPTY_RANGES),
++    LintId::of(redundant_clone::REDUNDANT_CLONE),
++    LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
++    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
++    LintId::of(redundant_slicing::REDUNDANT_SLICING),
++    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
++    LintId::of(reference::DEREF_ADDROF),
++    LintId::of(reference::REF_IN_DEREF),
++    LintId::of(regex::INVALID_REGEX),
++    LintId::of(repeat_once::REPEAT_ONCE),
++    LintId::of(returns::LET_AND_RETURN),
++    LintId::of(returns::NEEDLESS_RETURN),
++    LintId::of(self_assignment::SELF_ASSIGNMENT),
++    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
++    LintId::of(serde_api::SERDE_API_MISUSE),
++    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
++    LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
++    LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
++    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
++    LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
++    LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
++    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
++    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
++    LintId::of(swap::ALMOST_SWAPPED),
++    LintId::of(swap::MANUAL_SWAP),
++    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
++    LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
++    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
++    LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
++    LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
++    LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
++    LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
++    LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
++    LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
++    LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
++    LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
++    LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
++    LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
++    LintId::of(transmute::WRONG_TRANSMUTE),
++    LintId::of(transmuting_null::TRANSMUTING_NULL),
++    LintId::of(try_err::TRY_ERR),
++    LintId::of(types::BORROWED_BOX),
++    LintId::of(types::BOX_COLLECTION),
++    LintId::of(types::REDUNDANT_ALLOCATION),
++    LintId::of(types::TYPE_COMPLEXITY),
++    LintId::of(types::VEC_BOX),
++    LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
++    LintId::of(unicode::INVISIBLE_CHARACTERS),
++    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
++    LintId::of(unit_types::UNIT_ARG),
++    LintId::of(unit_types::UNIT_CMP),
++    LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
++    LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
++    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
++    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
++    LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
++    LintId::of(unused_unit::UNUSED_UNIT),
++    LintId::of(unwrap::PANICKING_UNWRAP),
++    LintId::of(unwrap::UNNECESSARY_UNWRAP),
++    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
++    LintId::of(useless_conversion::USELESS_CONVERSION),
++    LintId::of(vec::USELESS_VEC),
++    LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
++    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
++    LintId::of(write::PRINTLN_EMPTY_STRING),
++    LintId::of(write::PRINT_LITERAL),
++    LintId::of(write::PRINT_WITH_NEWLINE),
++    LintId::of(write::WRITELN_EMPTY_STRING),
++    LintId::of(write::WRITE_LITERAL),
++    LintId::of(write::WRITE_WITH_NEWLINE),
++    LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1809f2cc7d46278cac14ff0488d59e415ef4521c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
++    LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
++    LintId::of(feature_name::NEGATIVE_FEATURE_NAMES),
++    LintId::of(feature_name::REDUNDANT_FEATURE_NAMES),
++    LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
++    LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..64b82fc0faac8593504e6de0b0653504c5eb442d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,94 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
++    LintId::of(attrs::DEPRECATED_CFG_ATTR),
++    LintId::of(booleans::NONMINIMAL_BOOL),
++    LintId::of(casts::CHAR_LIT_AS_U8),
++    LintId::of(casts::UNNECESSARY_CAST),
++    LintId::of(derivable_impls::DERIVABLE_IMPLS),
++    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(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::MANUAL_FLATTEN),
++    LintId::of(loops::SINGLE_ELEMENT_LOOP),
++    LintId::of(loops::WHILE_LET_LOOP),
++    LintId::of(manual_strip::MANUAL_STRIP),
++    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
++    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_MAP_IDENTITY),
++    LintId::of(methods::FILTER_NEXT),
++    LintId::of(methods::FLAT_MAP_IDENTITY),
++    LintId::of(methods::INSPECT_FOR_EACH),
++    LintId::of(methods::ITER_COUNT),
++    LintId::of(methods::MANUAL_FILTER_MAP),
++    LintId::of(methods::MANUAL_FIND_MAP),
++    LintId::of(methods::MANUAL_SPLIT_ONCE),
++    LintId::of(methods::MAP_IDENTITY),
++    LintId::of(methods::OPTION_AS_REF_DEREF),
++    LintId::of(methods::OPTION_FILTER_MAP),
++    LintId::of(methods::SEARCH_IS_SOME),
++    LintId::of(methods::SKIP_WHILE_NEXT),
++    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_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
++    LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
++    LintId::of(needless_update::NEEDLESS_UPDATE),
++    LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
++    LintId::of(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(redundant_slicing::REDUNDANT_SLICING),
++    LintId::of(reference::DEREF_ADDROF),
++    LintId::of(reference::REF_IN_DEREF),
++    LintId::of(repeat_once::REPEAT_ONCE),
++    LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
++    LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
++    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_REF),
++    LintId::of(types::BORROWED_BOX),
++    LintId::of(types::TYPE_COMPLEXITY),
++    LintId::of(types::VEC_BOX),
++    LintId::of(unit_types::UNIT_ARG),
++    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),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e0ef7b3b8af9f06f71953b8f6018a57750f54a49
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,73 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
++    LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
++    LintId::of(approx_const::APPROX_CONSTANT),
++    LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
++    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(casts::CAST_REF_TO_MUT),
++    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_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(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::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::SUSPICIOUS_SPLITN),
++    LintId::of(methods::UNINIT_ASSUMED_INIT),
++    LintId::of(methods::ZST_OFFSET),
++    LintId::of(minmax::MIN_MAX),
++    LintId::of(misc::CMP_NAN),
++    LintId::of(misc::MODULO_ONE),
++    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
++    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
++    LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
++    LintId::of(ptr::INVALID_NULL_PTR_USAGE),
++    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(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
++    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(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
++    LintId::of(unicode::INVISIBLE_CHARACTERS),
++    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
++    LintId::of(unit_types::UNIT_CMP),
++    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),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c8c1e0262abaea8d62c774e6cad0b8764ab1c5b5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::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::IF_CHAIN_STYLE),
++    LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
++    LintId::of(utils::internal_lints::INVALID_PATHS),
++    LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
++    LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
++    LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
++    LintId::of(utils::internal_lints::PRODUCE_ICE),
++    LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2ba2b3da55cd1725c25822865525a7199aac83f7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,510 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_lints(&[
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::CLIPPY_LINTS_INTERNAL,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::COMPILER_LINT_FUNCTIONS,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::DEFAULT_LINT,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::IF_CHAIN_STYLE,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::INTERNING_DEFINED_SYMBOL,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::INVALID_PATHS,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::LINT_WITHOUT_LINT_PASS,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::OUTER_EXPN_EXPN_DATA,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::PRODUCE_ICE,
++    #[cfg(feature = "internal-lints")]
++    utils::internal_lints::UNNECESSARY_SYMBOL_STR,
++    absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
++    approx_const::APPROX_CONSTANT,
++    arithmetic::FLOAT_ARITHMETIC,
++    arithmetic::INTEGER_ARITHMETIC,
++    as_conversions::AS_CONVERSIONS,
++    asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
++    asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
++    assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
++    assign_ops::ASSIGN_OP_PATTERN,
++    assign_ops::MISREFACTORED_ASSIGN_OP,
++    async_yields_async::ASYNC_YIELDS_ASYNC,
++    attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
++    attrs::DEPRECATED_CFG_ATTR,
++    attrs::DEPRECATED_SEMVER,
++    attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
++    attrs::INLINE_ALWAYS,
++    attrs::MISMATCHED_TARGET_OS,
++    attrs::USELESS_ATTRIBUTE,
++    await_holding_invalid::AWAIT_HOLDING_LOCK,
++    await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
++    bit_mask::BAD_BIT_MASK,
++    bit_mask::INEFFECTIVE_BIT_MASK,
++    bit_mask::VERBOSE_BIT_MASK,
++    blacklisted_name::BLACKLISTED_NAME,
++    blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
++    bool_assert_comparison::BOOL_ASSERT_COMPARISON,
++    booleans::LOGIC_BUG,
++    booleans::NONMINIMAL_BOOL,
++    bytecount::NAIVE_BYTECOUNT,
++    cargo_common_metadata::CARGO_COMMON_METADATA,
++    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
++    casts::CAST_LOSSLESS,
++    casts::CAST_POSSIBLE_TRUNCATION,
++    casts::CAST_POSSIBLE_WRAP,
++    casts::CAST_PRECISION_LOSS,
++    casts::CAST_PTR_ALIGNMENT,
++    casts::CAST_REF_TO_MUT,
++    casts::CAST_SIGN_LOSS,
++    casts::CHAR_LIT_AS_U8,
++    casts::FN_TO_NUMERIC_CAST,
++    casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
++    casts::PTR_AS_PTR,
++    casts::UNNECESSARY_CAST,
++    checked_conversions::CHECKED_CONVERSIONS,
++    cognitive_complexity::COGNITIVE_COMPLEXITY,
++    collapsible_if::COLLAPSIBLE_ELSE_IF,
++    collapsible_if::COLLAPSIBLE_IF,
++    collapsible_match::COLLAPSIBLE_MATCH,
++    comparison_chain::COMPARISON_CHAIN,
++    copies::BRANCHES_SHARING_CODE,
++    copies::IFS_SAME_COND,
++    copies::IF_SAME_THEN_ELSE,
++    copies::SAME_FUNCTIONS_IN_IF_CONDITION,
++    copy_iterator::COPY_ITERATOR,
++    create_dir::CREATE_DIR,
++    dbg_macro::DBG_MACRO,
++    default::DEFAULT_TRAIT_ACCESS,
++    default::FIELD_REASSIGN_WITH_DEFAULT,
++    default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
++    dereference::EXPLICIT_DEREF_METHODS,
++    derivable_impls::DERIVABLE_IMPLS,
++    derive::DERIVE_HASH_XOR_EQ,
++    derive::DERIVE_ORD_XOR_PARTIAL_ORD,
++    derive::EXPL_IMPL_CLONE_ON_COPY,
++    derive::UNSAFE_DERIVE_DESERIALIZE,
++    disallowed_method::DISALLOWED_METHOD,
++    disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
++    disallowed_type::DISALLOWED_TYPE,
++    doc::DOC_MARKDOWN,
++    doc::MISSING_ERRORS_DOC,
++    doc::MISSING_PANICS_DOC,
++    doc::MISSING_SAFETY_DOC,
++    doc::NEEDLESS_DOCTEST_MAIN,
++    double_comparison::DOUBLE_COMPARISONS,
++    double_parens::DOUBLE_PARENS,
++    drop_forget_ref::DROP_COPY,
++    drop_forget_ref::DROP_REF,
++    drop_forget_ref::FORGET_COPY,
++    drop_forget_ref::FORGET_REF,
++    duration_subsec::DURATION_SUBSEC,
++    else_if_without_else::ELSE_IF_WITHOUT_ELSE,
++    empty_enum::EMPTY_ENUM,
++    entry::MAP_ENTRY,
++    enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
++    enum_variants::ENUM_VARIANT_NAMES,
++    enum_variants::MODULE_INCEPTION,
++    enum_variants::MODULE_NAME_REPETITIONS,
++    eq_op::EQ_OP,
++    eq_op::OP_REF,
++    equatable_if_let::EQUATABLE_IF_LET,
++    erasing_op::ERASING_OP,
++    escape::BOXED_LOCAL,
++    eta_reduction::REDUNDANT_CLOSURE,
++    eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
++    eval_order_dependence::DIVERGING_SUB_EXPRESSION,
++    eval_order_dependence::EVAL_ORDER_DEPENDENCE,
++    excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
++    excessive_bools::STRUCT_EXCESSIVE_BOOLS,
++    exhaustive_items::EXHAUSTIVE_ENUMS,
++    exhaustive_items::EXHAUSTIVE_STRUCTS,
++    exit::EXIT,
++    explicit_write::EXPLICIT_WRITE,
++    fallible_impl_from::FALLIBLE_IMPL_FROM,
++    feature_name::NEGATIVE_FEATURE_NAMES,
++    feature_name::REDUNDANT_FEATURE_NAMES,
++    float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
++    float_literal::EXCESSIVE_PRECISION,
++    float_literal::LOSSY_FLOAT_LITERAL,
++    floating_point_arithmetic::IMPRECISE_FLOPS,
++    floating_point_arithmetic::SUBOPTIMAL_FLOPS,
++    format::USELESS_FORMAT,
++    formatting::POSSIBLE_MISSING_COMMA,
++    formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
++    formatting::SUSPICIOUS_ELSE_FORMATTING,
++    formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
++    from_over_into::FROM_OVER_INTO,
++    from_str_radix_10::FROM_STR_RADIX_10,
++    functions::DOUBLE_MUST_USE,
++    functions::MUST_USE_CANDIDATE,
++    functions::MUST_USE_UNIT,
++    functions::NOT_UNSAFE_PTR_ARG_DEREF,
++    functions::RESULT_UNIT_ERR,
++    functions::TOO_MANY_ARGUMENTS,
++    functions::TOO_MANY_LINES,
++    future_not_send::FUTURE_NOT_SEND,
++    get_last_with_len::GET_LAST_WITH_LEN,
++    identity_op::IDENTITY_OP,
++    if_let_mutex::IF_LET_MUTEX,
++    if_not_else::IF_NOT_ELSE,
++    if_then_panic::IF_THEN_PANIC,
++    if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
++    implicit_hasher::IMPLICIT_HASHER,
++    implicit_return::IMPLICIT_RETURN,
++    implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
++    inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
++    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,
++    invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
++    items_after_statements::ITEMS_AFTER_STATEMENTS,
++    iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
++    large_const_arrays::LARGE_CONST_ARRAYS,
++    large_enum_variant::LARGE_ENUM_VARIANT,
++    large_stack_arrays::LARGE_STACK_ARRAYS,
++    len_zero::COMPARISON_TO_EMPTY,
++    len_zero::LEN_WITHOUT_IS_EMPTY,
++    len_zero::LEN_ZERO,
++    let_if_seq::USELESS_LET_IF_SEQ,
++    let_underscore::LET_UNDERSCORE_DROP,
++    let_underscore::LET_UNDERSCORE_LOCK,
++    let_underscore::LET_UNDERSCORE_MUST_USE,
++    lifetimes::EXTRA_UNUSED_LIFETIMES,
++    lifetimes::NEEDLESS_LIFETIMES,
++    literal_representation::DECIMAL_LITERAL_REPRESENTATION,
++    literal_representation::INCONSISTENT_DIGIT_GROUPING,
++    literal_representation::LARGE_DIGIT_GROUPS,
++    literal_representation::MISTYPED_LITERAL_SUFFIXES,
++    literal_representation::UNREADABLE_LITERAL,
++    literal_representation::UNUSUAL_BYTE_GROUPINGS,
++    loops::EMPTY_LOOP,
++    loops::EXPLICIT_COUNTER_LOOP,
++    loops::EXPLICIT_INTO_ITER_LOOP,
++    loops::EXPLICIT_ITER_LOOP,
++    loops::FOR_KV_MAP,
++    loops::FOR_LOOPS_OVER_FALLIBLES,
++    loops::ITER_NEXT_LOOP,
++    loops::MANUAL_FLATTEN,
++    loops::MANUAL_MEMCPY,
++    loops::MUT_RANGE_BOUND,
++    loops::NEEDLESS_COLLECT,
++    loops::NEEDLESS_RANGE_LOOP,
++    loops::NEVER_LOOP,
++    loops::SAME_ITEM_PUSH,
++    loops::SINGLE_ELEMENT_LOOP,
++    loops::WHILE_IMMUTABLE_CONDITION,
++    loops::WHILE_LET_LOOP,
++    loops::WHILE_LET_ON_ITERATOR,
++    macro_use::MACRO_USE_IMPORTS,
++    main_recursion::MAIN_RECURSION,
++    manual_async_fn::MANUAL_ASYNC_FN,
++    manual_map::MANUAL_MAP,
++    manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
++    manual_ok_or::MANUAL_OK_OR,
++    manual_strip::MANUAL_STRIP,
++    manual_unwrap_or::MANUAL_UNWRAP_OR,
++    map_clone::MAP_CLONE,
++    map_err_ignore::MAP_ERR_IGNORE,
++    map_unit_fn::OPTION_MAP_UNIT_FN,
++    map_unit_fn::RESULT_MAP_UNIT_FN,
++    match_on_vec_items::MATCH_ON_VEC_ITEMS,
++    match_result_ok::MATCH_RESULT_OK,
++    matches::INFALLIBLE_DESTRUCTURING_MATCH,
++    matches::MATCH_AS_REF,
++    matches::MATCH_BOOL,
++    matches::MATCH_LIKE_MATCHES_MACRO,
++    matches::MATCH_OVERLAPPING_ARM,
++    matches::MATCH_REF_PATS,
++    matches::MATCH_SAME_ARMS,
++    matches::MATCH_SINGLE_BINDING,
++    matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
++    matches::MATCH_WILD_ERR_ARM,
++    matches::REDUNDANT_PATTERN_MATCHING,
++    matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
++    matches::SINGLE_MATCH,
++    matches::SINGLE_MATCH_ELSE,
++    matches::WILDCARD_ENUM_MATCH_ARM,
++    matches::WILDCARD_IN_OR_PATTERNS,
++    mem_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::BYTES_NTH,
++    methods::CHARS_LAST_CMP,
++    methods::CHARS_NEXT_CMP,
++    methods::CLONED_INSTEAD_OF_COPIED,
++    methods::CLONE_DOUBLE_REF,
++    methods::CLONE_ON_COPY,
++    methods::CLONE_ON_REF_PTR,
++    methods::EXPECT_FUN_CALL,
++    methods::EXPECT_USED,
++    methods::EXTEND_WITH_DRAIN,
++    methods::FILETYPE_IS_FILE,
++    methods::FILTER_MAP_IDENTITY,
++    methods::FILTER_MAP_NEXT,
++    methods::FILTER_NEXT,
++    methods::FLAT_MAP_IDENTITY,
++    methods::FLAT_MAP_OPTION,
++    methods::FROM_ITER_INSTEAD_OF_COLLECT,
++    methods::GET_UNWRAP,
++    methods::IMPLICIT_CLONE,
++    methods::INEFFICIENT_TO_STRING,
++    methods::INSPECT_FOR_EACH,
++    methods::INTO_ITER_ON_REF,
++    methods::ITERATOR_STEP_BY_ZERO,
++    methods::ITER_CLONED_COLLECT,
++    methods::ITER_COUNT,
++    methods::ITER_NEXT_SLICE,
++    methods::ITER_NTH,
++    methods::ITER_NTH_ZERO,
++    methods::ITER_SKIP_NEXT,
++    methods::MANUAL_FILTER_MAP,
++    methods::MANUAL_FIND_MAP,
++    methods::MANUAL_SATURATING_ARITHMETIC,
++    methods::MANUAL_SPLIT_ONCE,
++    methods::MANUAL_STR_REPEAT,
++    methods::MAP_COLLECT_RESULT_UNIT,
++    methods::MAP_FLATTEN,
++    methods::MAP_IDENTITY,
++    methods::MAP_UNWRAP_OR,
++    methods::NEW_RET_NO_SELF,
++    methods::OK_EXPECT,
++    methods::OPTION_AS_REF_DEREF,
++    methods::OPTION_FILTER_MAP,
++    methods::OPTION_MAP_OR_NONE,
++    methods::OR_FUN_CALL,
++    methods::RESULT_MAP_OR_INTO_OPTION,
++    methods::SEARCH_IS_SOME,
++    methods::SHOULD_IMPLEMENT_TRAIT,
++    methods::SINGLE_CHAR_ADD_STR,
++    methods::SINGLE_CHAR_PATTERN,
++    methods::SKIP_WHILE_NEXT,
++    methods::STRING_EXTEND_CHARS,
++    methods::SUSPICIOUS_MAP,
++    methods::SUSPICIOUS_SPLITN,
++    methods::UNINIT_ASSUMED_INIT,
++    methods::UNNECESSARY_FILTER_MAP,
++    methods::UNNECESSARY_FOLD,
++    methods::UNNECESSARY_LAZY_EVALUATIONS,
++    methods::UNWRAP_OR_ELSE_DEFAULT,
++    methods::UNWRAP_USED,
++    methods::USELESS_ASREF,
++    methods::WRONG_SELF_CONVENTION,
++    methods::ZST_OFFSET,
++    minmax::MIN_MAX,
++    misc::CMP_NAN,
++    misc::CMP_OWNED,
++    misc::FLOAT_CMP,
++    misc::FLOAT_CMP_CONST,
++    misc::MODULO_ONE,
++    misc::SHORT_CIRCUIT_STATEMENT,
++    misc::TOPLEVEL_REF_ARG,
++    misc::USED_UNDERSCORE_BINDING,
++    misc::ZERO_PTR,
++    misc_early::BUILTIN_TYPE_SHADOW,
++    misc_early::DOUBLE_NEG,
++    misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
++    misc_early::MIXED_CASE_HEX_LITERALS,
++    misc_early::REDUNDANT_PATTERN,
++    misc_early::UNNEEDED_FIELD_PATTERN,
++    misc_early::UNNEEDED_WILDCARD_PATTERN,
++    misc_early::UNSEPARATED_LITERAL_SUFFIX,
++    misc_early::ZERO_PREFIXED_LITERAL,
++    missing_const_for_fn::MISSING_CONST_FOR_FN,
++    missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
++    missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
++    missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
++    module_style::MOD_MODULE_FILES,
++    module_style::SELF_NAMED_MODULE_FILES,
++    modulo_arithmetic::MODULO_ARITHMETIC,
++    multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
++    mut_key::MUTABLE_KEY_TYPE,
++    mut_mut::MUT_MUT,
++    mut_mutex_lock::MUT_MUTEX_LOCK,
++    mut_reference::UNNECESSARY_MUT_PASSED,
++    mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
++    mutex_atomic::MUTEX_ATOMIC,
++    mutex_atomic::MUTEX_INTEGER,
++    needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
++    needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
++    needless_bool::BOOL_COMPARISON,
++    needless_bool::NEEDLESS_BOOL,
++    needless_borrow::NEEDLESS_BORROW,
++    needless_borrow::REF_BINDING_TO_REFERENCE,
++    needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
++    needless_continue::NEEDLESS_CONTINUE,
++    needless_for_each::NEEDLESS_FOR_EACH,
++    needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
++    needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
++    needless_question_mark::NEEDLESS_QUESTION_MARK,
++    needless_update::NEEDLESS_UPDATE,
++    neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
++    neg_multiply::NEG_MULTIPLY,
++    new_without_default::NEW_WITHOUT_DEFAULT,
++    no_effect::NO_EFFECT,
++    no_effect::UNNECESSARY_OPERATION,
++    non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
++    non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
++    non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
++    non_expressive_names::MANY_SINGLE_CHAR_NAMES,
++    non_expressive_names::SIMILAR_NAMES,
++    non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
++    non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
++    nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
++    open_options::NONSENSICAL_OPEN_OPTIONS,
++    option_env_unwrap::OPTION_ENV_UNWRAP,
++    option_if_let_else::OPTION_IF_LET_ELSE,
++    overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
++    panic_in_result_fn::PANIC_IN_RESULT_FN,
++    panic_unimplemented::PANIC,
++    panic_unimplemented::TODO,
++    panic_unimplemented::UNIMPLEMENTED,
++    panic_unimplemented::UNREACHABLE,
++    partialeq_ne_impl::PARTIALEQ_NE_IMPL,
++    pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
++    pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
++    path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
++    pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
++    precedence::PRECEDENCE,
++    ptr::CMP_NULL,
++    ptr::INVALID_NULL_PTR_USAGE,
++    ptr::MUT_FROM_REF,
++    ptr::PTR_ARG,
++    ptr_eq::PTR_EQ,
++    ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
++    question_mark::QUESTION_MARK,
++    ranges::MANUAL_RANGE_CONTAINS,
++    ranges::RANGE_MINUS_ONE,
++    ranges::RANGE_PLUS_ONE,
++    ranges::RANGE_ZIP_WITH_LEN,
++    ranges::REVERSED_EMPTY_RANGES,
++    redundant_clone::REDUNDANT_CLONE,
++    redundant_closure_call::REDUNDANT_CLOSURE_CALL,
++    redundant_else::REDUNDANT_ELSE,
++    redundant_field_names::REDUNDANT_FIELD_NAMES,
++    redundant_pub_crate::REDUNDANT_PUB_CRATE,
++    redundant_slicing::REDUNDANT_SLICING,
++    redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
++    ref_option_ref::REF_OPTION_REF,
++    reference::DEREF_ADDROF,
++    reference::REF_IN_DEREF,
++    regex::INVALID_REGEX,
++    regex::TRIVIAL_REGEX,
++    repeat_once::REPEAT_ONCE,
++    returns::LET_AND_RETURN,
++    returns::NEEDLESS_RETURN,
++    same_name_method::SAME_NAME_METHOD,
++    self_assignment::SELF_ASSIGNMENT,
++    self_named_constructors::SELF_NAMED_CONSTRUCTORS,
++    semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
++    serde_api::SERDE_API_MISUSE,
++    shadow::SHADOW_REUSE,
++    shadow::SHADOW_SAME,
++    shadow::SHADOW_UNRELATED,
++    single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
++    size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
++    slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
++    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
++    strings::STRING_ADD,
++    strings::STRING_ADD_ASSIGN,
++    strings::STRING_FROM_UTF8_AS_BYTES,
++    strings::STRING_LIT_AS_BYTES,
++    strings::STRING_TO_STRING,
++    strings::STR_TO_STRING,
++    strlen_on_c_strings::STRLEN_ON_C_STRINGS,
++    suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
++    suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
++    suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
++    swap::ALMOST_SWAPPED,
++    swap::MANUAL_SWAP,
++    tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
++    temporary_assignment::TEMPORARY_ASSIGNMENT,
++    to_digit_is_some::TO_DIGIT_IS_SOME,
++    to_string_in_display::TO_STRING_IN_DISPLAY,
++    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,
++    try_err::TRY_ERR,
++    types::BORROWED_BOX,
++    types::BOX_COLLECTION,
++    types::LINKEDLIST,
++    types::OPTION_OPTION,
++    types::RC_BUFFER,
++    types::RC_MUTEX,
++    types::REDUNDANT_ALLOCATION,
++    types::TYPE_COMPLEXITY,
++    types::VEC_BOX,
++    undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
++    unicode::INVISIBLE_CHARACTERS,
++    unicode::NON_ASCII_LITERAL,
++    unicode::UNICODE_NOT_NFC,
++    unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
++    unit_types::LET_UNIT_VALUE,
++    unit_types::UNIT_ARG,
++    unit_types::UNIT_CMP,
++    unnamed_address::FN_ADDRESS_COMPARISONS,
++    unnamed_address::VTABLE_ADDRESS_COMPARISONS,
++    unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
++    unnecessary_sort_by::UNNECESSARY_SORT_BY,
++    unnecessary_wraps::UNNECESSARY_WRAPS,
++    unnested_or_patterns::UNNESTED_OR_PATTERNS,
++    unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
++    unused_async::UNUSED_ASYNC,
++    unused_io_amount::UNUSED_IO_AMOUNT,
++    unused_self::UNUSED_SELF,
++    unused_unit::UNUSED_UNIT,
++    unwrap::PANICKING_UNWRAP,
++    unwrap::UNNECESSARY_UNWRAP,
++    unwrap_in_result::UNWRAP_IN_RESULT,
++    upper_case_acronyms::UPPER_CASE_ACRONYMS,
++    use_self::USE_SELF,
++    useless_conversion::USELESS_CONVERSION,
++    vec::USELESS_VEC,
++    vec_init_then_push::VEC_INIT_THEN_PUSH,
++    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
++    verbose_file_reads::VERBOSE_FILE_READS,
++    wildcard_dependencies::WILDCARD_DEPENDENCIES,
++    wildcard_imports::ENUM_GLOB_USE,
++    wildcard_imports::WILDCARD_IMPORTS,
++    write::PRINTLN_EMPTY_STRING,
++    write::PRINT_LITERAL,
++    write::PRINT_STDERR,
++    write::PRINT_STDOUT,
++    write::PRINT_WITH_NEWLINE,
++    write::USE_DEBUG,
++    write::WRITELN_EMPTY_STRING,
++    write::WRITE_LITERAL,
++    write::WRITE_WITH_NEWLINE,
++    zero_div_zero::ZERO_DIVIDED_BY_ZERO,
++    zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..96e0b421094d622f4495a3a9be49085127a5841a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,30 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
++    LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
++    LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
++    LintId::of(copies::BRANCHES_SHARING_CODE),
++    LintId::of(disallowed_method::DISALLOWED_METHOD),
++    LintId::of(disallowed_type::DISALLOWED_TYPE),
++    LintId::of(equatable_if_let::EQUATABLE_IF_LET),
++    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(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
++    LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
++    LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
++    LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
++    LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
++    LintId::of(regex::TRIVIAL_REGEX),
++    LintId::of(strings::STRING_LIT_AS_BYTES),
++    LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
++    LintId::of(transmute::USELESS_TRANSMUTE),
++    LintId::of(use_self::USE_SELF),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6533b94e82bd5ce10c539392ca6a3c627480dbd1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,100 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
++    LintId::of(attrs::INLINE_ALWAYS),
++    LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
++    LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
++    LintId::of(bit_mask::VERBOSE_BIT_MASK),
++    LintId::of(bytecount::NAIVE_BYTECOUNT),
++    LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
++    LintId::of(casts::CAST_LOSSLESS),
++    LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
++    LintId::of(casts::CAST_POSSIBLE_WRAP),
++    LintId::of(casts::CAST_PRECISION_LOSS),
++    LintId::of(casts::CAST_PTR_ALIGNMENT),
++    LintId::of(casts::CAST_SIGN_LOSS),
++    LintId::of(casts::PTR_AS_PTR),
++    LintId::of(checked_conversions::CHECKED_CONVERSIONS),
++    LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
++    LintId::of(copy_iterator::COPY_ITERATOR),
++    LintId::of(default::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(doc::MISSING_PANICS_DOC),
++    LintId::of(empty_enum::EMPTY_ENUM),
++    LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
++    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_hasher::IMPLICIT_HASHER),
++    LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
++    LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
++    LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
++    LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
++    LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
++    LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
++    LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
++    LintId::of(let_underscore::LET_UNDERSCORE_DROP),
++    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(manual_ok_or::MANUAL_OK_OR),
++    LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
++    LintId::of(matches::MATCH_BOOL),
++    LintId::of(matches::MATCH_SAME_ARMS),
++    LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
++    LintId::of(matches::MATCH_WILD_ERR_ARM),
++    LintId::of(matches::SINGLE_MATCH_ELSE),
++    LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
++    LintId::of(methods::FILTER_MAP_NEXT),
++    LintId::of(methods::FLAT_MAP_OPTION),
++    LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
++    LintId::of(methods::IMPLICIT_CLONE),
++    LintId::of(methods::INEFFICIENT_TO_STRING),
++    LintId::of(methods::MAP_FLATTEN),
++    LintId::of(methods::MAP_UNWRAP_OR),
++    LintId::of(misc::FLOAT_CMP),
++    LintId::of(misc::USED_UNDERSCORE_BINDING),
++    LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
++    LintId::of(mut_mut::MUT_MUT),
++    LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
++    LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
++    LintId::of(needless_continue::NEEDLESS_CONTINUE),
++    LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
++    LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
++    LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
++    LintId::of(non_expressive_names::SIMILAR_NAMES),
++    LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
++    LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
++    LintId::of(ranges::RANGE_MINUS_ONE),
++    LintId::of(ranges::RANGE_PLUS_ONE),
++    LintId::of(redundant_else::REDUNDANT_ELSE),
++    LintId::of(ref_option_ref::REF_OPTION_REF),
++    LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
++    LintId::of(strings::STRING_ADD_ASSIGN),
++    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
++    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
++    LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
++    LintId::of(types::LINKEDLIST),
++    LintId::of(types::OPTION_OPTION),
++    LintId::of(unicode::NON_ASCII_LITERAL),
++    LintId::of(unicode::UNICODE_NOT_NFC),
++    LintId::of(unit_types::LET_UNIT_VALUE),
++    LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
++    LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
++    LintId::of(unused_async::UNUSED_ASYNC),
++    LintId::of(unused_self::UNUSED_SELF),
++    LintId::of(wildcard_imports::ENUM_GLOB_USE),
++    LintId::of(wildcard_imports::WILDCARD_IMPORTS),
++    LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5432345760bc3242126b9f0978e8d90d44d62e70
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
++    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::EXTEND_WITH_DRAIN),
++    LintId::of(methods::ITER_NTH),
++    LintId::of(methods::MANUAL_STR_REPEAT),
++    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_COLLECTION),
++    LintId::of(types::REDUNDANT_ALLOCATION),
++    LintId::of(vec::USELESS_VEC),
++    LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4463dea5fcb8436a12f82721865750869fc16cf1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
++    LintId::of(arithmetic::FLOAT_ARITHMETIC),
++    LintId::of(arithmetic::INTEGER_ARITHMETIC),
++    LintId::of(as_conversions::AS_CONVERSIONS),
++    LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
++    LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
++    LintId::of(create_dir::CREATE_DIR),
++    LintId::of(dbg_macro::DBG_MACRO),
++    LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
++    LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
++    LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
++    LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
++    LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
++    LintId::of(exit::EXIT),
++    LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
++    LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
++    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(map_err_ignore::MAP_ERR_IGNORE),
++    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(misc::FLOAT_CMP_CONST),
++    LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
++    LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
++    LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
++    LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
++    LintId::of(module_style::MOD_MODULE_FILES),
++    LintId::of(module_style::SELF_NAMED_MODULE_FILES),
++    LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
++    LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
++    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(same_name_method::SAME_NAME_METHOD),
++    LintId::of(shadow::SHADOW_REUSE),
++    LintId::of(shadow::SHADOW_SAME),
++    LintId::of(shadow::SHADOW_UNRELATED),
++    LintId::of(strings::STRING_ADD),
++    LintId::of(strings::STRING_TO_STRING),
++    LintId::of(strings::STR_TO_STRING),
++    LintId::of(types::RC_BUFFER),
++    LintId::of(types::RC_MUTEX),
++    LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
++    LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
++    LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
++    LintId::of(write::PRINT_STDERR),
++    LintId::of(write::PRINT_STDOUT),
++    LintId::of(write::USE_DEBUG),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a39c111c5742340d1a0d59723da29d722c8271c6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,114 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::style", Some("clippy_style"), vec![
++    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
++    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
++    LintId::of(blacklisted_name::BLACKLISTED_NAME),
++    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
++    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
++    LintId::of(casts::FN_TO_NUMERIC_CAST),
++    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
++    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
++    LintId::of(collapsible_if::COLLAPSIBLE_IF),
++    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
++    LintId::of(comparison_chain::COMPARISON_CHAIN),
++    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
++    LintId::of(doc::MISSING_SAFETY_DOC),
++    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
++    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
++    LintId::of(enum_variants::MODULE_INCEPTION),
++    LintId::of(eq_op::OP_REF),
++    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
++    LintId::of(float_literal::EXCESSIVE_PRECISION),
++    LintId::of(from_over_into::FROM_OVER_INTO),
++    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
++    LintId::of(functions::DOUBLE_MUST_USE),
++    LintId::of(functions::MUST_USE_UNIT),
++    LintId::of(functions::RESULT_UNIT_ERR),
++    LintId::of(if_then_panic::IF_THEN_PANIC),
++    LintId::of(inherent_to_string::INHERENT_TO_STRING),
++    LintId::of(len_zero::COMPARISON_TO_EMPTY),
++    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
++    LintId::of(len_zero::LEN_ZERO),
++    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
++    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
++    LintId::of(loops::FOR_KV_MAP),
++    LintId::of(loops::NEEDLESS_RANGE_LOOP),
++    LintId::of(loops::SAME_ITEM_PUSH),
++    LintId::of(loops::WHILE_LET_ON_ITERATOR),
++    LintId::of(main_recursion::MAIN_RECURSION),
++    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
++    LintId::of(manual_map::MANUAL_MAP),
++    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
++    LintId::of(map_clone::MAP_CLONE),
++    LintId::of(match_result_ok::MATCH_RESULT_OK),
++    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
++    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
++    LintId::of(matches::MATCH_OVERLAPPING_ARM),
++    LintId::of(matches::MATCH_REF_PATS),
++    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
++    LintId::of(matches::SINGLE_MATCH),
++    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
++    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
++    LintId::of(methods::BYTES_NTH),
++    LintId::of(methods::CHARS_LAST_CMP),
++    LintId::of(methods::CHARS_NEXT_CMP),
++    LintId::of(methods::INTO_ITER_ON_REF),
++    LintId::of(methods::ITER_CLONED_COLLECT),
++    LintId::of(methods::ITER_NEXT_SLICE),
++    LintId::of(methods::ITER_NTH_ZERO),
++    LintId::of(methods::ITER_SKIP_NEXT),
++    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
++    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
++    LintId::of(methods::NEW_RET_NO_SELF),
++    LintId::of(methods::OK_EXPECT),
++    LintId::of(methods::OPTION_MAP_OR_NONE),
++    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
++    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
++    LintId::of(methods::SINGLE_CHAR_ADD_STR),
++    LintId::of(methods::STRING_EXTEND_CHARS),
++    LintId::of(methods::UNNECESSARY_FOLD),
++    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
++    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
++    LintId::of(methods::WRONG_SELF_CONVENTION),
++    LintId::of(misc::TOPLEVEL_REF_ARG),
++    LintId::of(misc::ZERO_PTR),
++    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
++    LintId::of(misc_early::DOUBLE_NEG),
++    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
++    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
++    LintId::of(misc_early::REDUNDANT_PATTERN),
++    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
++    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
++    LintId::of(needless_borrow::NEEDLESS_BORROW),
++    LintId::of(neg_multiply::NEG_MULTIPLY),
++    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
++    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
++    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
++    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
++    LintId::of(ptr::CMP_NULL),
++    LintId::of(ptr::PTR_ARG),
++    LintId::of(ptr_eq::PTR_EQ),
++    LintId::of(question_mark::QUESTION_MARK),
++    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
++    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
++    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
++    LintId::of(returns::LET_AND_RETURN),
++    LintId::of(returns::NEEDLESS_RETURN),
++    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
++    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
++    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
++    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
++    LintId::of(try_err::TRY_ERR),
++    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
++    LintId::of(unused_unit::UNUSED_UNIT),
++    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
++    LintId::of(write::PRINTLN_EMPTY_STRING),
++    LintId::of(write::PRINT_LITERAL),
++    LintId::of(write::PRINT_WITH_NEWLINE),
++    LintId::of(write::WRITELN_EMPTY_STRING),
++    LintId::of(write::WRITE_LITERAL),
++    LintId::of(write::WRITE_WITH_NEWLINE),
++])
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8859787fbc830c97e7b34a0ee21e053d586bcdcf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++// This file was generated by `cargo dev update_lints`.
++// Use that command to update this file and do not edit by hand.
++// Manual edits will be overwritten.
++
++store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
++    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
++    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
++    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
++    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
++    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
++    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
++    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
++    LintId::of(loops::EMPTY_LOOP),
++    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
++    LintId::of(loops::MUT_RANGE_BOUND),
++    LintId::of(methods::SUSPICIOUS_MAP),
++    LintId::of(mut_key::MUTABLE_KEY_TYPE),
++    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
++    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
++])
index 897249174822cad0893287dcce17e81e74f1ddb0,0000000000000000000000000000000000000000..9fc6a9e0ccca073e30899604d6bf4c0747e2dd87
mode 100644,000000..100644
--- /dev/null
@@@ -1,2233 -1,0 +1,860 @@@
-     // 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::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::unused_collect",
-         "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
-     );
-     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",
-     );
-     store.register_removed(
-         "clippy::find_map",
-         "this lint has been replaced by `manual_find_map`, a more specific lint",
-     );
-     store.register_removed(
-         "clippy::filter_map",
-         "this lint has been replaced by `manual_filter_map`, a more specific lint",
-     );
-     store.register_removed(
-         "clippy::pub_enum_variant_names",
-         "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items",
-     );
-     store.register_removed(
-         "clippy::wrong_pub_self_convention",
-         "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items",
-     );
-     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 +// error-pattern:cargo-clippy
 +
 +#![feature(box_patterns)]
 +#![feature(drain_filter)]
 +#![feature(in_band_lifetimes)]
 +#![feature(iter_zip)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![feature(stmt_expr_attributes)]
 +#![feature(control_flow_enum)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_data_structures;
 +extern crate rustc_driver;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_pretty;
 +extern crate rustc_index;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_mir_dataflow;
 +extern crate rustc_parse;
 +extern crate rustc_parse_format;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +extern crate clippy_utils;
 +
 +use clippy_utils::parse_msrv;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_lint::LintId;
 +use rustc_session::Session;
 +
 +/// Macro used to declare a Clippy lint.
 +///
 +/// Every lint declaration consists of 4 parts:
 +///
 +/// 1. The documentation, which is used for the website
 +/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
 +/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
 +///    `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
 +/// 4. The `description` that contains a short explanation on what's wrong with code where the
 +///    lint is triggered.
 +///
 +/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
 +/// enabled by default. As said in the README.md of this repository, if the lint level mapping
 +/// changes, please update README.md.
 +///
 +/// # Example
 +///
 +/// ```
 +/// #![feature(rustc_private)]
 +/// extern crate rustc_session;
 +/// use rustc_session::declare_tool_lint;
 +/// use clippy_lints::declare_clippy_lint;
 +///
 +/// declare_clippy_lint! {
 +///     /// ### What it does
 +///     /// Checks for ... (describe what the lint matches).
 +///     ///
 +///     /// ### Why is this bad?
 +///     /// Supply the reason for linting the code.
 +///     ///
 +///     /// ### Example
 +///     /// ```rust
 +///     /// // Bad
 +///     /// Insert a short example of code that triggers the lint
 +///     ///
 +///     /// // Good
 +///     /// Insert a short example of improved code that doesn't trigger the lint
 +///     /// ```
 +///     pub LINT_NAME,
 +///     pedantic,
 +///     "description"
 +/// }
 +/// ```
 +/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +#[macro_export]
 +macro_rules! declare_clippy_lint {
 +    { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +}
 +
 +#[cfg(feature = "metadata-collector-lint")]
 +mod deprecated_lints;
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod absurd_extreme_comparisons;
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod async_yields_async;
 +mod attrs;
 +mod await_holding_invalid;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod bool_assert_comparison;
 +mod booleans;
 +mod bytecount;
 +mod cargo_common_metadata;
 +mod case_sensitive_file_extension_comparisons;
 +mod casts;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod collapsible_match;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod default_numeric_fallback;
 +mod dereference;
 +mod derivable_impls;
 +mod derive;
 +mod disallowed_method;
 +mod disallowed_script_idents;
 +mod disallowed_type;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duration_subsec;
 +mod else_if_without_else;
 +mod empty_enum;
 +mod entry;
 +mod enum_clike;
 +mod enum_variants;
 +mod eq_op;
++mod equatable_if_let;
 +mod erasing_op;
 +mod escape;
 +mod eta_reduction;
 +mod eval_order_dependence;
 +mod excessive_bools;
 +mod exhaustive_items;
 +mod exit;
 +mod explicit_write;
 +mod fallible_impl_from;
 +mod feature_name;
 +mod float_equality_without_abs;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod formatting;
 +mod from_over_into;
 +mod from_str_radix_10;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_not_else;
 +mod if_then_panic;
 +mod if_then_some_else_none;
 +mod implicit_hasher;
 +mod implicit_return;
 +mod implicit_saturating_sub;
 +mod inconsistent_struct_constructor;
 +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 invalid_upcast_comparisons;
 +mod items_after_statements;
 +mod iter_not_returning_iterator;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_stack_arrays;
 +mod len_zero;
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
 +mod manual_async_fn;
 +mod manual_map;
 +mod manual_non_exhaustive;
 +mod manual_ok_or;
 +mod manual_strip;
 +mod manual_unwrap_or;
 +mod map_clone;
 +mod map_err_ignore;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod match_result_ok;
 +mod 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_enforced_import_rename;
 +mod missing_inline;
 +mod module_style;
 +mod modulo_arithmetic;
 +mod multiple_crate_versions;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_mutex_lock;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bitwise_bool;
 +mod needless_bool;
 +mod needless_borrow;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_for_each;
 +mod needless_option_as_deref;
 +mod needless_pass_by_value;
 +mod needless_question_mark;
 +mod needless_update;
 +mod neg_cmp_op_on_partial_ord;
 +mod neg_multiply;
 +mod new_without_default;
 +mod no_effect;
 +mod non_copy_const;
 +mod non_expressive_names;
 +mod non_octal_unix_permissions;
++mod non_send_fields_in_send_ty;
 +mod nonstandard_macro_braces;
 +mod open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod pass_by_ref_or_value;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_eq;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_else;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_slicing;
 +mod redundant_static_lifetimes;
 +mod ref_option_ref;
 +mod reference;
 +mod regex;
 +mod repeat_once;
 +mod returns;
 +mod same_name_method;
 +mod self_assignment;
 +mod self_named_constructors;
 +mod semicolon_if_nothing_returned;
 +mod serde_api;
 +mod shadow;
 +mod single_component_path_imports;
 +mod size_of_in_element_count;
 +mod slow_vector_initialization;
 +mod stable_sort_primitive;
 +mod strings;
 +mod strlen_on_c_strings;
 +mod suspicious_operation_groupings;
 +mod suspicious_trait_impl;
 +mod swap;
 +mod tabs_in_doc_comments;
 +mod temporary_assignment;
 +mod to_digit_is_some;
 +mod to_string_in_display;
 +mod trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod try_err;
 +mod types;
 +mod undropped_manually_drops;
 +mod unicode;
 +mod unit_return_expecting_ord;
 +mod unit_types;
 +mod unnamed_address;
 +mod unnecessary_self_imports;
 +mod unnecessary_sort_by;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_async;
 +mod unused_io_amount;
 +mod unused_self;
 +mod unused_unit;
 +mod unwrap;
 +mod unwrap_in_result;
 +mod upper_case_acronyms;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_init_then_push;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_dependencies;
 +mod wildcard_imports;
 +mod write;
 +mod zero_div_zero;
 +mod zero_sized_map_values;
 +// end lints modules, do not remove this comment, it’s used in `update_lints`
 +
 +pub use crate::utils::conf::Conf;
 +use crate::utils::conf::TryConf;
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 +    // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
 +    store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
 +    store.register_pre_expansion_pass(|| Box::new(attrs::EarlyAttributes));
 +    store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro));
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(sess: &Session) -> Conf {
 +    let file_name = match utils::conf::lookup_conf_file() {
 +        Ok(Some(path)) => path,
 +        Ok(None) => return Conf::default(),
 +        Err(error) => {
 +            sess.struct_err(&format!("error finding Clippy's configuration file: {}", error))
 +                .emit();
 +            return Conf::default();
 +        },
 +    };
 +
 +    let TryConf { conf, errors } = utils::conf::read(&file_name);
 +    // all conf errors are non-fatal, we just use the default conf in case of error
 +    for error in errors {
 +        sess.struct_err(&format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            error
 +        ))
 +        .emit();
 +    }
 +
 +    conf
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +#[rustfmt::skip]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
-     // begin register lints, do not remove this comment, it’s used in `update_lints`
-     store.register_lints(&[
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::CLIPPY_LINTS_INTERNAL,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::COMPILER_LINT_FUNCTIONS,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::DEFAULT_LINT,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::IF_CHAIN_STYLE,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::INTERNING_DEFINED_SYMBOL,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::INVALID_PATHS,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::LINT_WITHOUT_LINT_PASS,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::OUTER_EXPN_EXPN_DATA,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::PRODUCE_ICE,
-         #[cfg(feature = "internal-lints")]
-         utils::internal_lints::UNNECESSARY_SYMBOL_STR,
-         absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
-         approx_const::APPROX_CONSTANT,
-         arithmetic::FLOAT_ARITHMETIC,
-         arithmetic::INTEGER_ARITHMETIC,
-         as_conversions::AS_CONVERSIONS,
-         asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
-         asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
-         assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
-         assign_ops::ASSIGN_OP_PATTERN,
-         assign_ops::MISREFACTORED_ASSIGN_OP,
-         async_yields_async::ASYNC_YIELDS_ASYNC,
-         attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
-         attrs::DEPRECATED_CFG_ATTR,
-         attrs::DEPRECATED_SEMVER,
-         attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
-         attrs::INLINE_ALWAYS,
-         attrs::MISMATCHED_TARGET_OS,
-         attrs::USELESS_ATTRIBUTE,
-         await_holding_invalid::AWAIT_HOLDING_LOCK,
-         await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
-         bit_mask::BAD_BIT_MASK,
-         bit_mask::INEFFECTIVE_BIT_MASK,
-         bit_mask::VERBOSE_BIT_MASK,
-         blacklisted_name::BLACKLISTED_NAME,
-         blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
-         bool_assert_comparison::BOOL_ASSERT_COMPARISON,
-         booleans::LOGIC_BUG,
-         booleans::NONMINIMAL_BOOL,
-         bytecount::NAIVE_BYTECOUNT,
-         cargo_common_metadata::CARGO_COMMON_METADATA,
-         case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-         casts::CAST_LOSSLESS,
-         casts::CAST_POSSIBLE_TRUNCATION,
-         casts::CAST_POSSIBLE_WRAP,
-         casts::CAST_PRECISION_LOSS,
-         casts::CAST_PTR_ALIGNMENT,
-         casts::CAST_REF_TO_MUT,
-         casts::CAST_SIGN_LOSS,
-         casts::CHAR_LIT_AS_U8,
-         casts::FN_TO_NUMERIC_CAST,
-         casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
-         casts::PTR_AS_PTR,
-         casts::UNNECESSARY_CAST,
-         checked_conversions::CHECKED_CONVERSIONS,
-         cognitive_complexity::COGNITIVE_COMPLEXITY,
-         collapsible_if::COLLAPSIBLE_ELSE_IF,
-         collapsible_if::COLLAPSIBLE_IF,
-         collapsible_match::COLLAPSIBLE_MATCH,
-         comparison_chain::COMPARISON_CHAIN,
-         copies::BRANCHES_SHARING_CODE,
-         copies::IFS_SAME_COND,
-         copies::IF_SAME_THEN_ELSE,
-         copies::SAME_FUNCTIONS_IN_IF_CONDITION,
-         copy_iterator::COPY_ITERATOR,
-         create_dir::CREATE_DIR,
-         dbg_macro::DBG_MACRO,
-         default::DEFAULT_TRAIT_ACCESS,
-         default::FIELD_REASSIGN_WITH_DEFAULT,
-         default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
-         dereference::EXPLICIT_DEREF_METHODS,
-         derivable_impls::DERIVABLE_IMPLS,
-         derive::DERIVE_HASH_XOR_EQ,
-         derive::DERIVE_ORD_XOR_PARTIAL_ORD,
-         derive::EXPL_IMPL_CLONE_ON_COPY,
-         derive::UNSAFE_DERIVE_DESERIALIZE,
-         disallowed_method::DISALLOWED_METHOD,
-         disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
-         disallowed_type::DISALLOWED_TYPE,
-         doc::DOC_MARKDOWN,
-         doc::MISSING_ERRORS_DOC,
-         doc::MISSING_PANICS_DOC,
-         doc::MISSING_SAFETY_DOC,
-         doc::NEEDLESS_DOCTEST_MAIN,
-         double_comparison::DOUBLE_COMPARISONS,
-         double_parens::DOUBLE_PARENS,
-         drop_forget_ref::DROP_COPY,
-         drop_forget_ref::DROP_REF,
-         drop_forget_ref::FORGET_COPY,
-         drop_forget_ref::FORGET_REF,
-         duration_subsec::DURATION_SUBSEC,
-         else_if_without_else::ELSE_IF_WITHOUT_ELSE,
-         empty_enum::EMPTY_ENUM,
-         entry::MAP_ENTRY,
-         enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
-         enum_variants::ENUM_VARIANT_NAMES,
-         enum_variants::MODULE_INCEPTION,
-         enum_variants::MODULE_NAME_REPETITIONS,
-         eq_op::EQ_OP,
-         eq_op::OP_REF,
-         erasing_op::ERASING_OP,
-         escape::BOXED_LOCAL,
-         eta_reduction::REDUNDANT_CLOSURE,
-         eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
-         eval_order_dependence::DIVERGING_SUB_EXPRESSION,
-         eval_order_dependence::EVAL_ORDER_DEPENDENCE,
-         excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
-         excessive_bools::STRUCT_EXCESSIVE_BOOLS,
-         exhaustive_items::EXHAUSTIVE_ENUMS,
-         exhaustive_items::EXHAUSTIVE_STRUCTS,
-         exit::EXIT,
-         explicit_write::EXPLICIT_WRITE,
-         fallible_impl_from::FALLIBLE_IMPL_FROM,
-         feature_name::NEGATIVE_FEATURE_NAMES,
-         feature_name::REDUNDANT_FEATURE_NAMES,
-         float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
-         float_literal::EXCESSIVE_PRECISION,
-         float_literal::LOSSY_FLOAT_LITERAL,
-         floating_point_arithmetic::IMPRECISE_FLOPS,
-         floating_point_arithmetic::SUBOPTIMAL_FLOPS,
-         format::USELESS_FORMAT,
-         formatting::POSSIBLE_MISSING_COMMA,
-         formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
-         formatting::SUSPICIOUS_ELSE_FORMATTING,
-         formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
-         from_over_into::FROM_OVER_INTO,
-         from_str_radix_10::FROM_STR_RADIX_10,
-         functions::DOUBLE_MUST_USE,
-         functions::MUST_USE_CANDIDATE,
-         functions::MUST_USE_UNIT,
-         functions::NOT_UNSAFE_PTR_ARG_DEREF,
-         functions::RESULT_UNIT_ERR,
-         functions::TOO_MANY_ARGUMENTS,
-         functions::TOO_MANY_LINES,
-         future_not_send::FUTURE_NOT_SEND,
-         get_last_with_len::GET_LAST_WITH_LEN,
-         identity_op::IDENTITY_OP,
-         if_let_mutex::IF_LET_MUTEX,
-         if_not_else::IF_NOT_ELSE,
-         if_then_panic::IF_THEN_PANIC,
-         if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
-         implicit_hasher::IMPLICIT_HASHER,
-         implicit_return::IMPLICIT_RETURN,
-         implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
-         inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
-         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,
-         invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
-         items_after_statements::ITEMS_AFTER_STATEMENTS,
-         iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
-         large_const_arrays::LARGE_CONST_ARRAYS,
-         large_enum_variant::LARGE_ENUM_VARIANT,
-         large_stack_arrays::LARGE_STACK_ARRAYS,
-         len_zero::COMPARISON_TO_EMPTY,
-         len_zero::LEN_WITHOUT_IS_EMPTY,
-         len_zero::LEN_ZERO,
-         let_if_seq::USELESS_LET_IF_SEQ,
-         let_underscore::LET_UNDERSCORE_DROP,
-         let_underscore::LET_UNDERSCORE_LOCK,
-         let_underscore::LET_UNDERSCORE_MUST_USE,
-         lifetimes::EXTRA_UNUSED_LIFETIMES,
-         lifetimes::NEEDLESS_LIFETIMES,
-         literal_representation::DECIMAL_LITERAL_REPRESENTATION,
-         literal_representation::INCONSISTENT_DIGIT_GROUPING,
-         literal_representation::LARGE_DIGIT_GROUPS,
-         literal_representation::MISTYPED_LITERAL_SUFFIXES,
-         literal_representation::UNREADABLE_LITERAL,
-         literal_representation::UNUSUAL_BYTE_GROUPINGS,
-         loops::EMPTY_LOOP,
-         loops::EXPLICIT_COUNTER_LOOP,
-         loops::EXPLICIT_INTO_ITER_LOOP,
-         loops::EXPLICIT_ITER_LOOP,
-         loops::FOR_KV_MAP,
-         loops::FOR_LOOPS_OVER_FALLIBLES,
-         loops::ITER_NEXT_LOOP,
-         loops::MANUAL_FLATTEN,
-         loops::MANUAL_MEMCPY,
-         loops::MUT_RANGE_BOUND,
-         loops::NEEDLESS_COLLECT,
-         loops::NEEDLESS_RANGE_LOOP,
-         loops::NEVER_LOOP,
-         loops::SAME_ITEM_PUSH,
-         loops::SINGLE_ELEMENT_LOOP,
-         loops::WHILE_IMMUTABLE_CONDITION,
-         loops::WHILE_LET_LOOP,
-         loops::WHILE_LET_ON_ITERATOR,
-         macro_use::MACRO_USE_IMPORTS,
-         main_recursion::MAIN_RECURSION,
-         manual_async_fn::MANUAL_ASYNC_FN,
-         manual_map::MANUAL_MAP,
-         manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
-         manual_ok_or::MANUAL_OK_OR,
-         manual_strip::MANUAL_STRIP,
-         manual_unwrap_or::MANUAL_UNWRAP_OR,
-         map_clone::MAP_CLONE,
-         map_err_ignore::MAP_ERR_IGNORE,
-         map_unit_fn::OPTION_MAP_UNIT_FN,
-         map_unit_fn::RESULT_MAP_UNIT_FN,
-         match_on_vec_items::MATCH_ON_VEC_ITEMS,
-         match_result_ok::MATCH_RESULT_OK,
-         matches::INFALLIBLE_DESTRUCTURING_MATCH,
-         matches::MATCH_AS_REF,
-         matches::MATCH_BOOL,
-         matches::MATCH_LIKE_MATCHES_MACRO,
-         matches::MATCH_OVERLAPPING_ARM,
-         matches::MATCH_REF_PATS,
-         matches::MATCH_SAME_ARMS,
-         matches::MATCH_SINGLE_BINDING,
-         matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
-         matches::MATCH_WILD_ERR_ARM,
-         matches::REDUNDANT_PATTERN_MATCHING,
-         matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
-         matches::SINGLE_MATCH,
-         matches::SINGLE_MATCH_ELSE,
-         matches::WILDCARD_ENUM_MATCH_ARM,
-         matches::WILDCARD_IN_OR_PATTERNS,
-         mem_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::BYTES_NTH,
-         methods::CHARS_LAST_CMP,
-         methods::CHARS_NEXT_CMP,
-         methods::CLONED_INSTEAD_OF_COPIED,
-         methods::CLONE_DOUBLE_REF,
-         methods::CLONE_ON_COPY,
-         methods::CLONE_ON_REF_PTR,
-         methods::EXPECT_FUN_CALL,
-         methods::EXPECT_USED,
-         methods::EXTEND_WITH_DRAIN,
-         methods::FILETYPE_IS_FILE,
-         methods::FILTER_MAP_IDENTITY,
-         methods::FILTER_MAP_NEXT,
-         methods::FILTER_NEXT,
-         methods::FLAT_MAP_IDENTITY,
-         methods::FLAT_MAP_OPTION,
-         methods::FROM_ITER_INSTEAD_OF_COLLECT,
-         methods::GET_UNWRAP,
-         methods::IMPLICIT_CLONE,
-         methods::INEFFICIENT_TO_STRING,
-         methods::INSPECT_FOR_EACH,
-         methods::INTO_ITER_ON_REF,
-         methods::ITERATOR_STEP_BY_ZERO,
-         methods::ITER_CLONED_COLLECT,
-         methods::ITER_COUNT,
-         methods::ITER_NEXT_SLICE,
-         methods::ITER_NTH,
-         methods::ITER_NTH_ZERO,
-         methods::ITER_SKIP_NEXT,
-         methods::MANUAL_FILTER_MAP,
-         methods::MANUAL_FIND_MAP,
-         methods::MANUAL_SATURATING_ARITHMETIC,
-         methods::MANUAL_SPLIT_ONCE,
-         methods::MANUAL_STR_REPEAT,
-         methods::MAP_COLLECT_RESULT_UNIT,
-         methods::MAP_FLATTEN,
-         methods::MAP_IDENTITY,
-         methods::MAP_UNWRAP_OR,
-         methods::NEW_RET_NO_SELF,
-         methods::OK_EXPECT,
-         methods::OPTION_AS_REF_DEREF,
-         methods::OPTION_FILTER_MAP,
-         methods::OPTION_MAP_OR_NONE,
-         methods::OR_FUN_CALL,
-         methods::RESULT_MAP_OR_INTO_OPTION,
-         methods::SEARCH_IS_SOME,
-         methods::SHOULD_IMPLEMENT_TRAIT,
-         methods::SINGLE_CHAR_ADD_STR,
-         methods::SINGLE_CHAR_PATTERN,
-         methods::SKIP_WHILE_NEXT,
-         methods::STRING_EXTEND_CHARS,
-         methods::SUSPICIOUS_MAP,
-         methods::SUSPICIOUS_SPLITN,
-         methods::UNINIT_ASSUMED_INIT,
-         methods::UNNECESSARY_FILTER_MAP,
-         methods::UNNECESSARY_FOLD,
-         methods::UNNECESSARY_LAZY_EVALUATIONS,
-         methods::UNWRAP_OR_ELSE_DEFAULT,
-         methods::UNWRAP_USED,
-         methods::USELESS_ASREF,
-         methods::WRONG_SELF_CONVENTION,
-         methods::ZST_OFFSET,
-         minmax::MIN_MAX,
-         misc::CMP_NAN,
-         misc::CMP_OWNED,
-         misc::FLOAT_CMP,
-         misc::FLOAT_CMP_CONST,
-         misc::MODULO_ONE,
-         misc::SHORT_CIRCUIT_STATEMENT,
-         misc::TOPLEVEL_REF_ARG,
-         misc::USED_UNDERSCORE_BINDING,
-         misc::ZERO_PTR,
-         misc_early::BUILTIN_TYPE_SHADOW,
-         misc_early::DOUBLE_NEG,
-         misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
-         misc_early::MIXED_CASE_HEX_LITERALS,
-         misc_early::REDUNDANT_PATTERN,
-         misc_early::UNNEEDED_FIELD_PATTERN,
-         misc_early::UNNEEDED_WILDCARD_PATTERN,
-         misc_early::UNSEPARATED_LITERAL_SUFFIX,
-         misc_early::ZERO_PREFIXED_LITERAL,
-         missing_const_for_fn::MISSING_CONST_FOR_FN,
-         missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
-         missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
-         missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
-         module_style::MOD_MODULE_FILES,
-         module_style::SELF_NAMED_MODULE_FILES,
-         modulo_arithmetic::MODULO_ARITHMETIC,
-         multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
-         mut_key::MUTABLE_KEY_TYPE,
-         mut_mut::MUT_MUT,
-         mut_mutex_lock::MUT_MUTEX_LOCK,
-         mut_reference::UNNECESSARY_MUT_PASSED,
-         mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
-         mutex_atomic::MUTEX_ATOMIC,
-         mutex_atomic::MUTEX_INTEGER,
-         needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
-         needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
-         needless_bool::BOOL_COMPARISON,
-         needless_bool::NEEDLESS_BOOL,
-         needless_borrow::NEEDLESS_BORROW,
-         needless_borrow::REF_BINDING_TO_REFERENCE,
-         needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
-         needless_continue::NEEDLESS_CONTINUE,
-         needless_for_each::NEEDLESS_FOR_EACH,
-         needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
-         needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
-         needless_question_mark::NEEDLESS_QUESTION_MARK,
-         needless_update::NEEDLESS_UPDATE,
-         neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
-         neg_multiply::NEG_MULTIPLY,
-         new_without_default::NEW_WITHOUT_DEFAULT,
-         no_effect::NO_EFFECT,
-         no_effect::UNNECESSARY_OPERATION,
-         non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
-         non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
-         non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
-         non_expressive_names::MANY_SINGLE_CHAR_NAMES,
-         non_expressive_names::SIMILAR_NAMES,
-         non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
-         nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
-         open_options::NONSENSICAL_OPEN_OPTIONS,
-         option_env_unwrap::OPTION_ENV_UNWRAP,
-         option_if_let_else::OPTION_IF_LET_ELSE,
-         overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
-         panic_in_result_fn::PANIC_IN_RESULT_FN,
-         panic_unimplemented::PANIC,
-         panic_unimplemented::TODO,
-         panic_unimplemented::UNIMPLEMENTED,
-         panic_unimplemented::UNREACHABLE,
-         partialeq_ne_impl::PARTIALEQ_NE_IMPL,
-         pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
-         pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
-         path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
-         pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
-         precedence::PRECEDENCE,
-         ptr::CMP_NULL,
-         ptr::INVALID_NULL_PTR_USAGE,
-         ptr::MUT_FROM_REF,
-         ptr::PTR_ARG,
-         ptr_eq::PTR_EQ,
-         ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
-         question_mark::QUESTION_MARK,
-         ranges::MANUAL_RANGE_CONTAINS,
-         ranges::RANGE_MINUS_ONE,
-         ranges::RANGE_PLUS_ONE,
-         ranges::RANGE_ZIP_WITH_LEN,
-         ranges::REVERSED_EMPTY_RANGES,
-         redundant_clone::REDUNDANT_CLONE,
-         redundant_closure_call::REDUNDANT_CLOSURE_CALL,
-         redundant_else::REDUNDANT_ELSE,
-         redundant_field_names::REDUNDANT_FIELD_NAMES,
-         redundant_pub_crate::REDUNDANT_PUB_CRATE,
-         redundant_slicing::REDUNDANT_SLICING,
-         redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
-         ref_option_ref::REF_OPTION_REF,
-         reference::DEREF_ADDROF,
-         reference::REF_IN_DEREF,
-         regex::INVALID_REGEX,
-         regex::TRIVIAL_REGEX,
-         repeat_once::REPEAT_ONCE,
-         returns::LET_AND_RETURN,
-         returns::NEEDLESS_RETURN,
-         same_name_method::SAME_NAME_METHOD,
-         self_assignment::SELF_ASSIGNMENT,
-         self_named_constructors::SELF_NAMED_CONSTRUCTORS,
-         semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
-         serde_api::SERDE_API_MISUSE,
-         shadow::SHADOW_REUSE,
-         shadow::SHADOW_SAME,
-         shadow::SHADOW_UNRELATED,
-         single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
-         size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
-         slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
-         stable_sort_primitive::STABLE_SORT_PRIMITIVE,
-         strings::STRING_ADD,
-         strings::STRING_ADD_ASSIGN,
-         strings::STRING_FROM_UTF8_AS_BYTES,
-         strings::STRING_LIT_AS_BYTES,
-         strings::STRING_TO_STRING,
-         strings::STR_TO_STRING,
-         strlen_on_c_strings::STRLEN_ON_C_STRINGS,
-         suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
-         suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
-         suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
-         swap::ALMOST_SWAPPED,
-         swap::MANUAL_SWAP,
-         tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
-         temporary_assignment::TEMPORARY_ASSIGNMENT,
-         to_digit_is_some::TO_DIGIT_IS_SOME,
-         to_string_in_display::TO_STRING_IN_DISPLAY,
-         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,
-         try_err::TRY_ERR,
-         types::BORROWED_BOX,
-         types::BOX_COLLECTION,
-         types::LINKEDLIST,
-         types::OPTION_OPTION,
-         types::RC_BUFFER,
-         types::RC_MUTEX,
-         types::REDUNDANT_ALLOCATION,
-         types::TYPE_COMPLEXITY,
-         types::VEC_BOX,
-         undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
-         unicode::INVISIBLE_CHARACTERS,
-         unicode::NON_ASCII_LITERAL,
-         unicode::UNICODE_NOT_NFC,
-         unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
-         unit_types::LET_UNIT_VALUE,
-         unit_types::UNIT_ARG,
-         unit_types::UNIT_CMP,
-         unnamed_address::FN_ADDRESS_COMPARISONS,
-         unnamed_address::VTABLE_ADDRESS_COMPARISONS,
-         unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
-         unnecessary_sort_by::UNNECESSARY_SORT_BY,
-         unnecessary_wraps::UNNECESSARY_WRAPS,
-         unnested_or_patterns::UNNESTED_OR_PATTERNS,
-         unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
-         unused_async::UNUSED_ASYNC,
-         unused_io_amount::UNUSED_IO_AMOUNT,
-         unused_self::UNUSED_SELF,
-         unused_unit::UNUSED_UNIT,
-         unwrap::PANICKING_UNWRAP,
-         unwrap::UNNECESSARY_UNWRAP,
-         unwrap_in_result::UNWRAP_IN_RESULT,
-         upper_case_acronyms::UPPER_CASE_ACRONYMS,
-         use_self::USE_SELF,
-         useless_conversion::USELESS_CONVERSION,
-         vec::USELESS_VEC,
-         vec_init_then_push::VEC_INIT_THEN_PUSH,
-         vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
-         verbose_file_reads::VERBOSE_FILE_READS,
-         wildcard_dependencies::WILDCARD_DEPENDENCIES,
-         wildcard_imports::ENUM_GLOB_USE,
-         wildcard_imports::WILDCARD_IMPORTS,
-         write::PRINTLN_EMPTY_STRING,
-         write::PRINT_LITERAL,
-         write::PRINT_STDERR,
-         write::PRINT_STDOUT,
-         write::PRINT_WITH_NEWLINE,
-         write::USE_DEBUG,
-         write::WRITELN_EMPTY_STRING,
-         write::WRITE_LITERAL,
-         write::WRITE_WITH_NEWLINE,
-         zero_div_zero::ZERO_DIVIDED_BY_ZERO,
-         zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
-     ]);
-     // end register lints, do not remove this comment, it’s used in `update_lints`
-     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(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
-         LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
-         LintId::of(create_dir::CREATE_DIR),
-         LintId::of(dbg_macro::DBG_MACRO),
-         LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
-         LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
-         LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
-         LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
-         LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
-         LintId::of(exit::EXIT),
-         LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
-         LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
-         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(map_err_ignore::MAP_ERR_IGNORE),
-         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(misc::FLOAT_CMP_CONST),
-         LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
-         LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
-         LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
-         LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
-         LintId::of(module_style::MOD_MODULE_FILES),
-         LintId::of(module_style::SELF_NAMED_MODULE_FILES),
-         LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
-         LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
-         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(same_name_method::SAME_NAME_METHOD),
-         LintId::of(shadow::SHADOW_REUSE),
-         LintId::of(shadow::SHADOW_SAME),
-         LintId::of(strings::STRING_ADD),
-         LintId::of(strings::STRING_TO_STRING),
-         LintId::of(strings::STR_TO_STRING),
-         LintId::of(types::RC_BUFFER),
-         LintId::of(types::RC_MUTEX),
-         LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
-         LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
-         LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
-         LintId::of(write::PRINT_STDERR),
-         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_invalid::AWAIT_HOLDING_LOCK),
-         LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
-         LintId::of(bit_mask::VERBOSE_BIT_MASK),
-         LintId::of(bytecount::NAIVE_BYTECOUNT),
-         LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
-         LintId::of(casts::CAST_LOSSLESS),
-         LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
-         LintId::of(casts::CAST_POSSIBLE_WRAP),
-         LintId::of(casts::CAST_PRECISION_LOSS),
-         LintId::of(casts::CAST_PTR_ALIGNMENT),
-         LintId::of(casts::CAST_SIGN_LOSS),
-         LintId::of(casts::PTR_AS_PTR),
-         LintId::of(checked_conversions::CHECKED_CONVERSIONS),
-         LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
-         LintId::of(copy_iterator::COPY_ITERATOR),
-         LintId::of(default::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(doc::MISSING_PANICS_DOC),
-         LintId::of(empty_enum::EMPTY_ENUM),
-         LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
-         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_hasher::IMPLICIT_HASHER),
-         LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
-         LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
-         LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
-         LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
-         LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
-         LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
-         LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
-         LintId::of(let_underscore::LET_UNDERSCORE_DROP),
-         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(manual_ok_or::MANUAL_OK_OR),
-         LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
-         LintId::of(matches::MATCH_BOOL),
-         LintId::of(matches::MATCH_SAME_ARMS),
-         LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
-         LintId::of(matches::MATCH_WILD_ERR_ARM),
-         LintId::of(matches::SINGLE_MATCH_ELSE),
-         LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
-         LintId::of(methods::FILTER_MAP_NEXT),
-         LintId::of(methods::FLAT_MAP_OPTION),
-         LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
-         LintId::of(methods::IMPLICIT_CLONE),
-         LintId::of(methods::INEFFICIENT_TO_STRING),
-         LintId::of(methods::MAP_FLATTEN),
-         LintId::of(methods::MAP_UNWRAP_OR),
-         LintId::of(misc::FLOAT_CMP),
-         LintId::of(misc::USED_UNDERSCORE_BINDING),
-         LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
-         LintId::of(mut_mut::MUT_MUT),
-         LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
-         LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
-         LintId::of(needless_continue::NEEDLESS_CONTINUE),
-         LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
-         LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
-         LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
-         LintId::of(non_expressive_names::SIMILAR_NAMES),
-         LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
-         LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
-         LintId::of(ranges::RANGE_MINUS_ONE),
-         LintId::of(ranges::RANGE_PLUS_ONE),
-         LintId::of(redundant_else::REDUNDANT_ELSE),
-         LintId::of(ref_option_ref::REF_OPTION_REF),
-         LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
-         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(transmute::TRANSMUTE_PTR_TO_PTR),
-         LintId::of(types::LINKEDLIST),
-         LintId::of(types::OPTION_OPTION),
-         LintId::of(unicode::NON_ASCII_LITERAL),
-         LintId::of(unicode::UNICODE_NOT_NFC),
-         LintId::of(unit_types::LET_UNIT_VALUE),
-         LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
-         LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
-         LintId::of(unused_async::UNUSED_ASYNC),
-         LintId::of(unused_self::UNUSED_SELF),
-         LintId::of(wildcard_imports::ENUM_GLOB_USE),
-         LintId::of(wildcard_imports::WILDCARD_IMPORTS),
-         LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
-     ]);
++    include!("lib.deprecated.rs");
 +
-     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::IF_CHAIN_STYLE),
-         LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
-         LintId::of(utils::internal_lints::INVALID_PATHS),
-         LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
-         LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
-         LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
-         LintId::of(utils::internal_lints::PRODUCE_ICE),
-         LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
-     ]);
-     store.register_group(true, "clippy::all", Some("clippy"), vec![
-         LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
-         LintId::of(approx_const::APPROX_CONSTANT),
-         LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-         LintId::of(assign_ops::ASSIGN_OP_PATTERN),
-         LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
-         LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
-         LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
-         LintId::of(attrs::DEPRECATED_CFG_ATTR),
-         LintId::of(attrs::DEPRECATED_SEMVER),
-         LintId::of(attrs::MISMATCHED_TARGET_OS),
-         LintId::of(attrs::USELESS_ATTRIBUTE),
-         LintId::of(bit_mask::BAD_BIT_MASK),
-         LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
-         LintId::of(blacklisted_name::BLACKLISTED_NAME),
-         LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
-         LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
-         LintId::of(booleans::LOGIC_BUG),
-         LintId::of(booleans::NONMINIMAL_BOOL),
-         LintId::of(casts::CAST_REF_TO_MUT),
-         LintId::of(casts::CHAR_LIT_AS_U8),
-         LintId::of(casts::FN_TO_NUMERIC_CAST),
-         LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-         LintId::of(casts::UNNECESSARY_CAST),
-         LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
-         LintId::of(collapsible_if::COLLAPSIBLE_IF),
-         LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
-         LintId::of(comparison_chain::COMPARISON_CHAIN),
-         LintId::of(copies::IFS_SAME_COND),
-         LintId::of(copies::IF_SAME_THEN_ELSE),
-         LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
-         LintId::of(derivable_impls::DERIVABLE_IMPLS),
-         LintId::of(derive::DERIVE_HASH_XOR_EQ),
-         LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
-         LintId::of(doc::MISSING_SAFETY_DOC),
-         LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
-         LintId::of(double_comparison::DOUBLE_COMPARISONS),
-         LintId::of(double_parens::DOUBLE_PARENS),
-         LintId::of(drop_forget_ref::DROP_COPY),
-         LintId::of(drop_forget_ref::DROP_REF),
-         LintId::of(drop_forget_ref::FORGET_COPY),
-         LintId::of(drop_forget_ref::FORGET_REF),
-         LintId::of(duration_subsec::DURATION_SUBSEC),
-         LintId::of(entry::MAP_ENTRY),
-         LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
-         LintId::of(enum_variants::ENUM_VARIANT_NAMES),
-         LintId::of(enum_variants::MODULE_INCEPTION),
-         LintId::of(eq_op::EQ_OP),
-         LintId::of(eq_op::OP_REF),
-         LintId::of(erasing_op::ERASING_OP),
-         LintId::of(escape::BOXED_LOCAL),
-         LintId::of(eta_reduction::REDUNDANT_CLOSURE),
-         LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
-         LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
-         LintId::of(explicit_write::EXPLICIT_WRITE),
-         LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
-         LintId::of(float_literal::EXCESSIVE_PRECISION),
-         LintId::of(format::USELESS_FORMAT),
-         LintId::of(formatting::POSSIBLE_MISSING_COMMA),
-         LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
-         LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
-         LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
-         LintId::of(from_over_into::FROM_OVER_INTO),
-         LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
-         LintId::of(functions::DOUBLE_MUST_USE),
-         LintId::of(functions::MUST_USE_UNIT),
-         LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
-         LintId::of(functions::RESULT_UNIT_ERR),
-         LintId::of(functions::TOO_MANY_ARGUMENTS),
-         LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
-         LintId::of(identity_op::IDENTITY_OP),
-         LintId::of(if_let_mutex::IF_LET_MUTEX),
-         LintId::of(if_then_panic::IF_THEN_PANIC),
-         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::COMPARISON_TO_EMPTY),
-         LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
-         LintId::of(len_zero::LEN_ZERO),
-         LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
-         LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
-         LintId::of(lifetimes::NEEDLESS_LIFETIMES),
-         LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
-         LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
-         LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
-         LintId::of(loops::EMPTY_LOOP),
-         LintId::of(loops::EXPLICIT_COUNTER_LOOP),
-         LintId::of(loops::FOR_KV_MAP),
-         LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
-         LintId::of(loops::ITER_NEXT_LOOP),
-         LintId::of(loops::MANUAL_FLATTEN),
-         LintId::of(loops::MANUAL_MEMCPY),
-         LintId::of(loops::MUT_RANGE_BOUND),
-         LintId::of(loops::NEEDLESS_COLLECT),
-         LintId::of(loops::NEEDLESS_RANGE_LOOP),
-         LintId::of(loops::NEVER_LOOP),
-         LintId::of(loops::SAME_ITEM_PUSH),
-         LintId::of(loops::SINGLE_ELEMENT_LOOP),
-         LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
-         LintId::of(loops::WHILE_LET_LOOP),
-         LintId::of(loops::WHILE_LET_ON_ITERATOR),
-         LintId::of(main_recursion::MAIN_RECURSION),
-         LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
-         LintId::of(manual_map::MANUAL_MAP),
-         LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-         LintId::of(manual_strip::MANUAL_STRIP),
-         LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
-         LintId::of(map_clone::MAP_CLONE),
-         LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
-         LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
-         LintId::of(match_result_ok::MATCH_RESULT_OK),
-         LintId::of(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::BYTES_NTH),
-         LintId::of(methods::CHARS_LAST_CMP),
-         LintId::of(methods::CHARS_NEXT_CMP),
-         LintId::of(methods::CLONE_DOUBLE_REF),
-         LintId::of(methods::CLONE_ON_COPY),
-         LintId::of(methods::EXPECT_FUN_CALL),
-         LintId::of(methods::EXTEND_WITH_DRAIN),
-         LintId::of(methods::FILTER_MAP_IDENTITY),
-         LintId::of(methods::FILTER_NEXT),
-         LintId::of(methods::FLAT_MAP_IDENTITY),
-         LintId::of(methods::INSPECT_FOR_EACH),
-         LintId::of(methods::INTO_ITER_ON_REF),
-         LintId::of(methods::ITERATOR_STEP_BY_ZERO),
-         LintId::of(methods::ITER_CLONED_COLLECT),
-         LintId::of(methods::ITER_COUNT),
-         LintId::of(methods::ITER_NEXT_SLICE),
-         LintId::of(methods::ITER_NTH),
-         LintId::of(methods::ITER_NTH_ZERO),
-         LintId::of(methods::ITER_SKIP_NEXT),
-         LintId::of(methods::MANUAL_FILTER_MAP),
-         LintId::of(methods::MANUAL_FIND_MAP),
-         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
-         LintId::of(methods::MANUAL_SPLIT_ONCE),
-         LintId::of(methods::MANUAL_STR_REPEAT),
-         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
-         LintId::of(methods::MAP_IDENTITY),
-         LintId::of(methods::NEW_RET_NO_SELF),
-         LintId::of(methods::OK_EXPECT),
-         LintId::of(methods::OPTION_AS_REF_DEREF),
-         LintId::of(methods::OPTION_FILTER_MAP),
-         LintId::of(methods::OPTION_MAP_OR_NONE),
-         LintId::of(methods::OR_FUN_CALL),
-         LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
-         LintId::of(methods::SEARCH_IS_SOME),
-         LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
-         LintId::of(methods::SINGLE_CHAR_ADD_STR),
-         LintId::of(methods::SINGLE_CHAR_PATTERN),
-         LintId::of(methods::SKIP_WHILE_NEXT),
-         LintId::of(methods::STRING_EXTEND_CHARS),
-         LintId::of(methods::SUSPICIOUS_MAP),
-         LintId::of(methods::SUSPICIOUS_SPLITN),
-         LintId::of(methods::UNINIT_ASSUMED_INIT),
-         LintId::of(methods::UNNECESSARY_FILTER_MAP),
-         LintId::of(methods::UNNECESSARY_FOLD),
-         LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
-         LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
-         LintId::of(methods::USELESS_ASREF),
-         LintId::of(methods::WRONG_SELF_CONVENTION),
-         LintId::of(methods::ZST_OFFSET),
-         LintId::of(minmax::MIN_MAX),
-         LintId::of(misc::CMP_NAN),
-         LintId::of(misc::CMP_OWNED),
-         LintId::of(misc::MODULO_ONE),
-         LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
-         LintId::of(misc::TOPLEVEL_REF_ARG),
-         LintId::of(misc::ZERO_PTR),
-         LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
-         LintId::of(misc_early::DOUBLE_NEG),
-         LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
-         LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
-         LintId::of(misc_early::REDUNDANT_PATTERN),
-         LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
-         LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
-         LintId::of(mut_key::MUTABLE_KEY_TYPE),
-         LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
-         LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
-         LintId::of(mutex_atomic::MUTEX_ATOMIC),
-         LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
-         LintId::of(needless_bool::BOOL_COMPARISON),
-         LintId::of(needless_bool::NEEDLESS_BOOL),
-         LintId::of(needless_borrow::NEEDLESS_BORROW),
-         LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
-         LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
-         LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
-         LintId::of(needless_update::NEEDLESS_UPDATE),
-         LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
-         LintId::of(neg_multiply::NEG_MULTIPLY),
-         LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
-         LintId::of(no_effect::NO_EFFECT),
-         LintId::of(no_effect::UNNECESSARY_OPERATION),
-         LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-         LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
-         LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
-         LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
-         LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
-         LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
-         LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
-         LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
-         LintId::of(precedence::PRECEDENCE),
-         LintId::of(ptr::CMP_NULL),
-         LintId::of(ptr::INVALID_NULL_PTR_USAGE),
-         LintId::of(ptr::MUT_FROM_REF),
-         LintId::of(ptr::PTR_ARG),
-         LintId::of(ptr_eq::PTR_EQ),
-         LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-         LintId::of(question_mark::QUESTION_MARK),
-         LintId::of(ranges::MANUAL_RANGE_CONTAINS),
-         LintId::of(ranges::RANGE_ZIP_WITH_LEN),
-         LintId::of(ranges::REVERSED_EMPTY_RANGES),
-         LintId::of(redundant_clone::REDUNDANT_CLONE),
-         LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
-         LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
-         LintId::of(redundant_slicing::REDUNDANT_SLICING),
-         LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-         LintId::of(reference::DEREF_ADDROF),
-         LintId::of(reference::REF_IN_DEREF),
-         LintId::of(regex::INVALID_REGEX),
-         LintId::of(repeat_once::REPEAT_ONCE),
-         LintId::of(returns::LET_AND_RETURN),
-         LintId::of(returns::NEEDLESS_RETURN),
-         LintId::of(self_assignment::SELF_ASSIGNMENT),
-         LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
-         LintId::of(serde_api::SERDE_API_MISUSE),
-         LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-         LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
-         LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
-         LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
-         LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
-         LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
-         LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
-         LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
-         LintId::of(swap::ALMOST_SWAPPED),
-         LintId::of(swap::MANUAL_SWAP),
-         LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
-         LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
-         LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
-         LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
-         LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
-         LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
-         LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
-         LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
-         LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
-         LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
-         LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
-         LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
-         LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
-         LintId::of(transmute::WRONG_TRANSMUTE),
-         LintId::of(transmuting_null::TRANSMUTING_NULL),
-         LintId::of(try_err::TRY_ERR),
-         LintId::of(types::BORROWED_BOX),
-         LintId::of(types::BOX_COLLECTION),
-         LintId::of(types::REDUNDANT_ALLOCATION),
-         LintId::of(types::TYPE_COMPLEXITY),
-         LintId::of(types::VEC_BOX),
-         LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
-         LintId::of(unicode::INVISIBLE_CHARACTERS),
-         LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
-         LintId::of(unit_types::UNIT_ARG),
-         LintId::of(unit_types::UNIT_CMP),
-         LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
-         LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
-         LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
-         LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
-         LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
-         LintId::of(unused_unit::UNUSED_UNIT),
-         LintId::of(unwrap::PANICKING_UNWRAP),
-         LintId::of(unwrap::UNNECESSARY_UNWRAP),
-         LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
-         LintId::of(useless_conversion::USELESS_CONVERSION),
-         LintId::of(vec::USELESS_VEC),
-         LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
-         LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
-         LintId::of(write::PRINTLN_EMPTY_STRING),
-         LintId::of(write::PRINT_LITERAL),
-         LintId::of(write::PRINT_WITH_NEWLINE),
-         LintId::of(write::WRITELN_EMPTY_STRING),
-         LintId::of(write::WRITE_LITERAL),
-         LintId::of(write::WRITE_WITH_NEWLINE),
-         LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
-     ]);
-     store.register_group(true, "clippy::style", Some("clippy_style"), vec![
-         LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-         LintId::of(assign_ops::ASSIGN_OP_PATTERN),
-         LintId::of(blacklisted_name::BLACKLISTED_NAME),
-         LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
-         LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
-         LintId::of(casts::FN_TO_NUMERIC_CAST),
-         LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-         LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
-         LintId::of(collapsible_if::COLLAPSIBLE_IF),
-         LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
-         LintId::of(comparison_chain::COMPARISON_CHAIN),
-         LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
-         LintId::of(doc::MISSING_SAFETY_DOC),
-         LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
-         LintId::of(enum_variants::ENUM_VARIANT_NAMES),
-         LintId::of(enum_variants::MODULE_INCEPTION),
-         LintId::of(eq_op::OP_REF),
-         LintId::of(eta_reduction::REDUNDANT_CLOSURE),
-         LintId::of(float_literal::EXCESSIVE_PRECISION),
-         LintId::of(from_over_into::FROM_OVER_INTO),
-         LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
-         LintId::of(functions::DOUBLE_MUST_USE),
-         LintId::of(functions::MUST_USE_UNIT),
-         LintId::of(functions::RESULT_UNIT_ERR),
-         LintId::of(if_then_panic::IF_THEN_PANIC),
-         LintId::of(inherent_to_string::INHERENT_TO_STRING),
-         LintId::of(len_zero::COMPARISON_TO_EMPTY),
-         LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
-         LintId::of(len_zero::LEN_ZERO),
-         LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
-         LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
-         LintId::of(loops::FOR_KV_MAP),
-         LintId::of(loops::NEEDLESS_RANGE_LOOP),
-         LintId::of(loops::SAME_ITEM_PUSH),
-         LintId::of(loops::WHILE_LET_ON_ITERATOR),
-         LintId::of(main_recursion::MAIN_RECURSION),
-         LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
-         LintId::of(manual_map::MANUAL_MAP),
-         LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-         LintId::of(map_clone::MAP_CLONE),
-         LintId::of(match_result_ok::MATCH_RESULT_OK),
-         LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
-         LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
-         LintId::of(matches::MATCH_OVERLAPPING_ARM),
-         LintId::of(matches::MATCH_REF_PATS),
-         LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
-         LintId::of(matches::SINGLE_MATCH),
-         LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
-         LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
-         LintId::of(methods::BYTES_NTH),
-         LintId::of(methods::CHARS_LAST_CMP),
-         LintId::of(methods::CHARS_NEXT_CMP),
-         LintId::of(methods::INTO_ITER_ON_REF),
-         LintId::of(methods::ITER_CLONED_COLLECT),
-         LintId::of(methods::ITER_NEXT_SLICE),
-         LintId::of(methods::ITER_NTH_ZERO),
-         LintId::of(methods::ITER_SKIP_NEXT),
-         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
-         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
-         LintId::of(methods::NEW_RET_NO_SELF),
-         LintId::of(methods::OK_EXPECT),
-         LintId::of(methods::OPTION_MAP_OR_NONE),
-         LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
-         LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
-         LintId::of(methods::SINGLE_CHAR_ADD_STR),
-         LintId::of(methods::STRING_EXTEND_CHARS),
-         LintId::of(methods::UNNECESSARY_FOLD),
-         LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
-         LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
-         LintId::of(methods::WRONG_SELF_CONVENTION),
-         LintId::of(misc::TOPLEVEL_REF_ARG),
-         LintId::of(misc::ZERO_PTR),
-         LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
-         LintId::of(misc_early::DOUBLE_NEG),
-         LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
-         LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
-         LintId::of(misc_early::REDUNDANT_PATTERN),
-         LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
-         LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
-         LintId::of(needless_borrow::NEEDLESS_BORROW),
-         LintId::of(neg_multiply::NEG_MULTIPLY),
-         LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
-         LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-         LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
-         LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
-         LintId::of(ptr::CMP_NULL),
-         LintId::of(ptr::PTR_ARG),
-         LintId::of(ptr_eq::PTR_EQ),
-         LintId::of(question_mark::QUESTION_MARK),
-         LintId::of(ranges::MANUAL_RANGE_CONTAINS),
-         LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
-         LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-         LintId::of(returns::LET_AND_RETURN),
-         LintId::of(returns::NEEDLESS_RETURN),
-         LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
-         LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-         LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
-         LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
-         LintId::of(try_err::TRY_ERR),
-         LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
-         LintId::of(unused_unit::UNUSED_UNIT),
-         LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
-         LintId::of(write::PRINTLN_EMPTY_STRING),
-         LintId::of(write::PRINT_LITERAL),
-         LintId::of(write::PRINT_WITH_NEWLINE),
-         LintId::of(write::WRITELN_EMPTY_STRING),
-         LintId::of(write::WRITE_LITERAL),
-         LintId::of(write::WRITE_WITH_NEWLINE),
-     ]);
-     store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
-         LintId::of(attrs::DEPRECATED_CFG_ATTR),
-         LintId::of(booleans::NONMINIMAL_BOOL),
-         LintId::of(casts::CHAR_LIT_AS_U8),
-         LintId::of(casts::UNNECESSARY_CAST),
-         LintId::of(derivable_impls::DERIVABLE_IMPLS),
-         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(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::MANUAL_FLATTEN),
-         LintId::of(loops::SINGLE_ELEMENT_LOOP),
-         LintId::of(loops::WHILE_LET_LOOP),
-         LintId::of(manual_strip::MANUAL_STRIP),
-         LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
-         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_MAP_IDENTITY),
-         LintId::of(methods::FILTER_NEXT),
-         LintId::of(methods::FLAT_MAP_IDENTITY),
-         LintId::of(methods::INSPECT_FOR_EACH),
-         LintId::of(methods::ITER_COUNT),
-         LintId::of(methods::MANUAL_FILTER_MAP),
-         LintId::of(methods::MANUAL_FIND_MAP),
-         LintId::of(methods::MANUAL_SPLIT_ONCE),
-         LintId::of(methods::MAP_IDENTITY),
-         LintId::of(methods::OPTION_AS_REF_DEREF),
-         LintId::of(methods::OPTION_FILTER_MAP),
-         LintId::of(methods::SEARCH_IS_SOME),
-         LintId::of(methods::SKIP_WHILE_NEXT),
-         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_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
-         LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
-         LintId::of(needless_update::NEEDLESS_UPDATE),
-         LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
-         LintId::of(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(redundant_slicing::REDUNDANT_SLICING),
-         LintId::of(reference::DEREF_ADDROF),
-         LintId::of(reference::REF_IN_DEREF),
-         LintId::of(repeat_once::REPEAT_ONCE),
-         LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
-         LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
-         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_REF),
-         LintId::of(types::BORROWED_BOX),
-         LintId::of(types::TYPE_COMPLEXITY),
-         LintId::of(types::VEC_BOX),
-         LintId::of(unit_types::UNIT_ARG),
-         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(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
-         LintId::of(approx_const::APPROX_CONSTANT),
-         LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
-         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(casts::CAST_REF_TO_MUT),
-         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_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(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::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::SUSPICIOUS_SPLITN),
-         LintId::of(methods::UNINIT_ASSUMED_INIT),
-         LintId::of(methods::ZST_OFFSET),
-         LintId::of(minmax::MIN_MAX),
-         LintId::of(misc::CMP_NAN),
-         LintId::of(misc::MODULO_ONE),
-         LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
-         LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
-         LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
-         LintId::of(ptr::INVALID_NULL_PTR_USAGE),
-         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(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
-         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(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
-         LintId::of(unicode::INVISIBLE_CHARACTERS),
-         LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
-         LintId::of(unit_types::UNIT_CMP),
-         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::suspicious", None, vec![
-         LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
-         LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
-         LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
-         LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
-         LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
-         LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
-         LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
-         LintId::of(loops::EMPTY_LOOP),
-         LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
-         LintId::of(loops::MUT_RANGE_BOUND),
-         LintId::of(methods::SUSPICIOUS_MAP),
-         LintId::of(mut_key::MUTABLE_KEY_TYPE),
-         LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
-         LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
-     ]);
-     store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
-         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::EXTEND_WITH_DRAIN),
-         LintId::of(methods::ITER_NTH),
-         LintId::of(methods::MANUAL_STR_REPEAT),
-         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_COLLECTION),
-         LintId::of(types::REDUNDANT_ALLOCATION),
-         LintId::of(vec::USELESS_VEC),
-         LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
-     ]);
-     store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
-         LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
-         LintId::of(feature_name::NEGATIVE_FEATURE_NAMES),
-         LintId::of(feature_name::REDUNDANT_FEATURE_NAMES),
-         LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
-         LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
-     ]);
++    include!("lib.register_lints.rs");
++    include!("lib.register_restriction.rs");
++    include!("lib.register_pedantic.rs");
 +
 +    #[cfg(feature = "internal-lints")]
-     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(copies::BRANCHES_SHARING_CODE),
-         LintId::of(disallowed_method::DISALLOWED_METHOD),
-         LintId::of(disallowed_type::DISALLOWED_TYPE),
-         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(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
-         LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
-         LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
-         LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
-         LintId::of(regex::TRIVIAL_REGEX),
-         LintId::of(strings::STRING_LIT_AS_BYTES),
-         LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
-         LintId::of(transmute::USELESS_TRANSMUTE),
-         LintId::of(use_self::USE_SELF),
-     ]);
++    include!("lib.register_internal.rs");
 +
-     store.register_late_pass(|| Box::new(shadow::Shadow));
++    include!("lib.register_all.rs");
++    include!("lib.register_style.rs");
++    include!("lib.register_complexity.rs");
++    include!("lib.register_correctness.rs");
++    include!("lib.register_suspicious.rs");
++    include!("lib.register_perf.rs");
++    include!("lib.register_cargo.rs");
++    include!("lib.register_nursery.rs");
 +
 +    #[cfg(feature = "metadata-collector-lint")]
 +    {
 +        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
 +            store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
 +            return;
 +        }
 +    }
 +
 +    // all the internal lints
 +    #[cfg(feature = "internal-lints")]
 +    {
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
 +        store.register_late_pass(|| Box::new(utils::inspector::DeepCodeInspector));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
 +    }
 +
 +    store.register_late_pass(|| Box::new(utils::author::Author));
 +    store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
 +    store.register_late_pass(|| Box::new(serde_api::SerdeApi));
 +    let vec_box_size_threshold = conf.vec_box_size_threshold;
 +    let type_complexity_threshold = conf.type_complexity_threshold;
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move || Box::new(types::Types::new(
 +        vec_box_size_threshold,
 +        type_complexity_threshold,
 +        avoid_breaking_exported_api,
 +    )));
 +    store.register_late_pass(|| Box::new(booleans::NonminimalBool));
 +    store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool));
 +    store.register_late_pass(|| Box::new(eq_op::EqOp));
 +    store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
 +    store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move || Box::new(bit_mask::BitMask::new(verbose_bit_mask_threshold)));
 +    store.register_late_pass(|| Box::new(ptr::Ptr));
 +    store.register_late_pass(|| Box::new(ptr_eq::PtrEq));
 +    store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
 +    store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref));
 +    store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
 +    store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
 +    store.register_late_pass(|| Box::new(misc::MiscLints));
 +    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
 +    store.register_late_pass(|| Box::new(identity_op::IdentityOp));
 +    store.register_late_pass(|| Box::new(erasing_op::ErasingOp));
 +    store.register_late_pass(|| Box::new(mut_mut::MutMut));
 +    store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed));
 +    store.register_late_pass(|| Box::new(len_zero::LenZero));
 +    store.register_late_pass(|| Box::new(attrs::Attributes));
 +    store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
 +    store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
 +    store.register_late_pass(|| Box::new(unicode::Unicode));
 +    store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
 +    store.register_late_pass(|| Box::new(strings::StringAdd));
 +    store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
 +    store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
 +    store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback));
 +    store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
 +    store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
 +    store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 +
 +    let msrv = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
 +            None
 +        })
 +    });
 +
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
 +    store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv)));
 +    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
 +    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::new(msrv)));
 +    store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
 +    store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv)));
 +    store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv)));
 +    store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv)));
 +    store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv)));
 +    store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv)));
 +    store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
 +    store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
 +    store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
 +    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
 +
 +    store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
 +    store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
 +    store.register_late_pass(|| Box::new(map_clone::MapClone));
 +    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
++    store.register_late_pass(|| Box::new(shadow::Shadow::default()));
 +    store.register_late_pass(|| Box::new(unit_types::UnitTypes));
 +    store.register_late_pass(|| Box::new(loops::Loops));
 +    store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
 +    store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
 +    store.register_late_pass(|| Box::new(entry::HashMapPass));
 +    store.register_late_pass(|| Box::new(minmax::MinMaxPass));
 +    store.register_late_pass(|| Box::new(open_options::OpenOptions));
 +    store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
 +    store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
 +    store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
 +    store.register_late_pass(|| Box::new(needless_borrow::NeedlessBorrow::default()));
 +    store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
 +    store.register_late_pass(|| Box::new(no_effect::NoEffect));
 +    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
 +    store.register_late_pass(|| Box::new(transmute::Transmute));
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move || Box::new(cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)));
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move || Box::new(escape::BoxedLocal{too_large_for_stack}));
 +    store.register_late_pass(move || Box::new(vec::UselessVec{too_large_for_stack}));
 +    store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
 +    store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
 +    store.register_late_pass(|| Box::new(derive::Derive));
 +    store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
 +    store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen));
 +    store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
 +    store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
 +    store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons));
 +    store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
 +    store.register_late_pass(|| Box::new(regex::Regex));
 +    store.register_late_pass(|| Box::new(copies::CopyAndPaste));
 +    store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
 +    store.register_late_pass(|| Box::new(format::UselessFormat));
 +    store.register_late_pass(|| Box::new(swap::Swap));
 +    store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
 +    store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
 +    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || Box::new(functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold)));
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
 +    store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
 +    store.register_late_pass(|| Box::new(mem_discriminant::MemDiscriminant));
 +    store.register_late_pass(|| Box::new(mem_forget::MemForget));
 +    store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
 +    store.register_late_pass(|| Box::new(assign_ops::AssignOps));
 +    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
 +    store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence));
 +    store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
 +    store.register_late_pass(|| Box::new(missing_inline::MissingInline));
 +    store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
 +    store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
 +    store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
 +    store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
 +    store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite));
 +    store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue));
 +    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
 +        conf.trivial_copy_size_limit,
 +        conf.pass_by_value_size_limit,
 +        conf.avoid_breaking_exported_api,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move || Box::new(pass_by_ref_or_value));
 +    store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
 +    store.register_late_pass(|| Box::new(try_err::TryErr));
 +    store.register_late_pass(|| Box::new(bytecount::ByteCount));
 +    store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
 +    store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
 +    store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
 +    store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher));
 +    store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom));
 +    store.register_late_pass(|| Box::new(double_comparison::DoubleComparisons));
 +    store.register_late_pass(|| Box::new(question_mark::QuestionMark));
 +    store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
 +    store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl));
 +    store.register_late_pass(|| Box::new(map_unit_fn::MapUnit));
 +    store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
 +    store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
 +    store.register_late_pass(|| Box::new(unwrap::Unwrap));
 +    store.register_late_pass(|| Box::new(duration_subsec::DurationSubsec));
 +    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
 +    store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
 +    store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
 +    store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
 +    store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
 +    store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
 +    store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
 +    store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
 +    store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
 +    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
 +    store.register_late_pass(|| Box::new(integer_division::IntegerDivision));
 +    store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
 +    store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain));
 +    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
 +    store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
 +    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
 +    store.register_early_pass(|| Box::new(reference::RefInDeref));
 +    store.register_early_pass(|| Box::new(double_parens::DoubleParens));
 +    store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
 +    store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
 +    store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
 +    store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
 +    store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
 +    store.register_early_pass(|| Box::new(formatting::Formatting));
 +    store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
 +    store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
 +    store.register_late_pass(|| Box::new(returns::Return));
 +    store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
 +    store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
 +    store.register_early_pass(|| Box::new(precedence::Precedence));
 +    store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
 +    store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
 +    store.register_late_pass(|| Box::new(create_dir::CreateDir));
 +    store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
 +    let cargo_ignore_publish = conf.cargo_ignore_publish;
 +    store.register_late_pass(move || Box::new(cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)));
 +    store.register_late_pass(|| Box::new(multiple_crate_versions::MultipleCrateVersions));
 +    store.register_late_pass(|| Box::new(wildcard_dependencies::WildcardDependencies));
 +    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
 +    store.register_early_pass(move || Box::new(literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)));
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)));
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_late_pass(move || Box::new(enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api)));
 +    store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
 +    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
 +    store.register_late_pass(move || Box::new(upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive)));
 +    store.register_late_pass(|| Box::new(default::Default::default()));
 +    store.register_late_pass(|| Box::new(unused_self::UnusedSelf));
 +    store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
 +    store.register_late_pass(|| Box::new(exit::Exit));
 +    store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome));
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
 +    store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
 +    store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
 +    store.register_early_pass(|| Box::new(as_conversions::AsConversions));
 +    store.register_late_pass(|| Box::new(let_underscore::LetUnderscore));
 +    store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_early_pass(move || Box::new(excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)));
 +    store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
 +    store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads));
 +    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
 +    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
 +    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
 +    store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
 +    store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
 +    store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
++    store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
 +    store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
 +    store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
 +    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
 +    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
 +    store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || Box::new(non_expressive_names::NonExpressiveNames {
 +        single_char_binding_names_threshold,
 +    }));
 +    let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
 +    store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
 +    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
 +    store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
 +    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
 +    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
 +    store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
 +    store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
 +    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
 +    store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
 +    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
 +    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
 +    let disallowed_methods = conf.disallowed_methods.clone();
 +    store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(disallowed_methods.clone())));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
 +    store.register_late_pass(|| Box::new(undropped_manually_drops::UndroppedManuallyDrops));
 +    store.register_late_pass(|| Box::new(strings::StrToString));
 +    store.register_late_pass(|| Box::new(strings::StringToString));
 +    store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
 +    store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
 +    store.register_late_pass(|| Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons));
 +    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
 +    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
 +    store.register_late_pass(|| Box::new(manual_map::ManualMap));
 +    store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
 +    store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
 +    store.register_early_pass(move || Box::new(module_style::ModStyle));
 +    store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
 +    let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types)));
 +    let import_renames = conf.enforced_import_renames.clone();
 +    store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
 +    let scripts = conf.allowed_scripts.clone();
 +    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
 +    store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
 +    store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
 +    store.register_late_pass(move || Box::new(feature_name::FeatureName));
 +    store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
 +    store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
++    let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
++    store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
 +}
 +
 +#[rustfmt::skip]
 +fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_removed(
 +        "should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "reverse_range_loop",
 +        "this lint is now included in reversed_empty_ranges",
 +    );
 +}
 +
 +/// Register renamed lints.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
 +    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
 +    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
 +    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
 +    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
 +    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
 +    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
 +    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
 +    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 +    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 +    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
 +
 +    // uplifted lints
 +    ls.register_renamed("clippy::invalid_ref", "invalid_value");
 +    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
 +    ls.register_renamed("clippy::unused_label", "unused_labels");
 +    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
 +    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
 +    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
 +    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
 +    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
 +}
 +
 +// 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 358d53e8859d08d06a7b72ff565da1f0f5608118,0000000000000000000000000000000000000000..aedf0844937d1a2327cbf3a96307cbe4c931a01b
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,174 @@@
-         if let ty::BorrowKind::MutBorrow = bk {
 +use super::MUT_RANGE_BOUND;
 +use clippy_utils::diagnostics::span_lint_and_note;
 +use clippy_utils::{get_enclosing_block, higher, path_to_local};
 +use if_chain::if_chain;
 +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 +use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::{mir::FakeReadCause, ty};
 +use rustc_span::source_map::Span;
 +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 +
 +pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
 +    if_chain! {
 +        if let Some(higher::Range {
 +            start: Some(start),
 +            end: Some(end),
 +            ..
 +        }) = higher::Range::hir(arg);
 +        let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end));
 +        if mut_id_start.is_some() || mut_id_end.is_some();
 +        then {
 +            let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end);
 +            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_and_note(
 +            cx,
 +            MUT_RANGE_BOUND,
 +            sp,
 +            "attempt to mutate range bound within loop",
 +            None,
 +            "the range of the loop is unchanged",
 +        );
 +    }
 +}
 +
 +fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
 +    if_chain! {
 +        if let Some(hir_id) = path_to_local(bound);
 +        if let Node::Binding(pat) = cx.tcx.hir().get(hir_id);
 +        if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
 +        then {
 +            return Some(hir_id);
 +        }
 +    }
 +    None
 +}
 +
 +fn check_for_mutation<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    body: &Expr<'_>,
 +    bound_id_start: Option<HirId>,
 +    bound_id_end: Option<HirId>,
 +) -> (Option<Span>, Option<Span>) {
 +    let mut delegate = MutatePairDelegate {
 +        cx,
 +        hir_id_low: bound_id_start,
 +        hir_id_high: bound_id_end,
 +        span_low: None,
 +        span_high: None,
 +    };
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        ExprUseVisitor::new(
 +            &mut delegate,
 +            &infcx,
 +            body.hir_id.owner,
 +            cx.param_env,
 +            cx.typeck_results(),
 +        )
 +        .walk_expr(body);
 +    });
 +
 +    delegate.mutation_span()
 +}
 +
 +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>, _: HirId) {}
 +
 +    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
++        if bk == ty::BorrowKind::MutBorrow {
 +            if let PlaceBase::Local(id) = cmt.place.base {
 +                if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
 +                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
 +                }
 +                if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
 +                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
 +                }
 +            }
 +        }
 +    }
 +
 +    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
 +        if let PlaceBase::Local(id) = cmt.place.base {
 +            if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
 +                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
 +            }
 +            if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
 +                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
 +            }
 +        }
 +    }
 +
 +    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
 +}
 +
 +impl MutatePairDelegate<'_, '_> {
 +    fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
 +        (self.span_low, self.span_high)
 +    }
 +}
 +
 +struct BreakAfterExprVisitor {
 +    hir_id: HirId,
 +    past_expr: bool,
 +    past_candidate: bool,
 +    break_after_expr: bool,
 +}
 +
 +impl BreakAfterExprVisitor {
 +    pub fn is_found(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +        let mut visitor = BreakAfterExprVisitor {
 +            hir_id,
 +            past_expr: false,
 +            past_candidate: false,
 +            break_after_expr: false,
 +        };
 +
 +        get_enclosing_block(cx, hir_id).map_or(false, |block| {
 +            visitor.visit_block(block);
 +            visitor.break_after_expr
 +        })
 +    }
 +}
 +
 +impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 +        if self.past_candidate {
 +            return;
 +        }
 +
 +        if expr.hir_id == self.hir_id {
 +            self.past_expr = true;
 +        } else if self.past_expr {
 +            if matches!(&expr.kind, ExprKind::Break(..)) {
 +                self.break_after_expr = true;
 +            }
 +
 +            self.past_candidate = true;
 +        } else {
 +            intravisit::walk_expr(self, expr);
 +        }
 +    }
 +}
index 7157b80118558b889cc41556e071dd71891a903e,0000000000000000000000000000000000000000..172d9fc39a29fb8975254f0e266a7fdf59ae663a
mode 100644,000000..100644
--- /dev/null
@@@ -1,382 -1,0 +1,382 @@@
-                         if let BinOpKind::Add = op.node {
 +use super::NEEDLESS_RANGE_LOOP;
 +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::has_iter_method;
 +use clippy_utils::visitors::is_local_used;
 +use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
 +use if_chain::if_chain;
 +use rustc_ast::ast;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::middle::region;
 +use rustc_middle::ty::{self, Ty};
 +use rustc_span::symbol::{sym, Symbol};
 +use std::iter::{self, Iterator};
 +use std::mem;
 +
 +/// 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)]
 +pub(super) fn check<'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::hir(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 if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
 +                    return;
 +                } 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, left, right) = end.kind {
++                        if op.node == BinOpKind::Add {
 +                            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 if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
 +                        return;
 +                    } 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,
 +                        arg.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,
 +                        arg.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(method, _, len_args, _) = expr.kind;
 +        if len_args.len() == 1;
 +        if method.ident.name == sym::len;
 +        if let ExprKind::Path(QPath::Resolved(_, 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
 +}
 +
 +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, seqvar) = *seqpath;
 +            if seqvar.segments.len() == 1;
 +            if is_local_used(self.cx, idx, self.var);
 +            then {
 +                if self.prefer_mutable {
 +                    self.indexed_mut.insert(seqvar.segments[0].ident.name);
 +                }
 +                let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
 +                let res = self.cx.qpath_res(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 index_used_directly {
 +                            self.indexed_directly.insert(
 +                                seqvar.segments[0].ident.name,
 +                                (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
 +                            );
 +                        } else {
 +                            self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
 +                        }
 +                        return false;  // no need to walk further *on the variable*
 +                    }
 +                    Res::Def(DefKind::Static | DefKind::Const, ..) => {
 +                        if index_used_directly {
 +                            self.indexed_directly.insert(
 +                                seqvar.segments[0].ident.name,
 +                                (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
 +                            );
 +                        } else {
 +                            self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
 +                        }
 +                        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(meth, _, [args_0, args_1, ..], _) = &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(seqexpr, idx) = expr.kind;
 +            if !self.check(idx, seqexpr, expr);
 +            then { return }
 +        }
 +
 +        if_chain! {
 +            // directly using a variable
 +            if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind;
 +            if let Res::Local(local_id) = path.res;
 +            then {
 +                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(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
 +                self.prefer_mutable = true;
 +                self.visit_expr(lhs);
 +                self.prefer_mutable = false;
 +                self.visit_expr(rhs);
 +            },
 +            ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
 +                if mutbl == Mutability::Mut {
 +                    self.prefer_mutable = true;
 +                }
 +                self.visit_expr(expr);
 +            },
 +            ExprKind::Call(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 iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), 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
 +    }
 +}
index 41956650c9f4e7c8a000926f8aa8d7d2b0894207,0000000000000000000000000000000000000000..c0fde5e51663e63a4609c8fafb6b3f04a1742f8a
mode 100644,000000..100644
--- /dev/null
@@@ -1,207 -1,0 +1,207 @@@
-                         if let LoopSource::ForLoop = source;
 +use super::utils::make_iterator_snippet;
 +use super::NEVER_LOOP;
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::higher::ForLoop;
 +use clippy_utils::source::snippet;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind};
 +use rustc_lint::LateContext;
 +use std::iter::{once, Iterator};
 +
 +pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +    if let ExprKind::Loop(block, _, source, _) = expr.kind {
 +        match never_loop_block(block, expr.hir_id) {
 +            NeverLoopResult::AlwaysBreak => {
 +                span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| {
 +                    if_chain! {
++                        if source == LoopSource::ForLoop;
 +                        if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
 +                        if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match);
 +                        then {
 +                            // Suggests using an `if let` instead. This is `Unspecified` because the
 +                            // loop may (probably) contain `break` statements which would be invalid
 +                            // in an `if let`.
 +                            diag.span_suggestion_verbose(
 +                                for_span.with_hi(iterator.span.hi()),
 +                                "if you need the first element of the iterator, try writing",
 +                                for_to_if_let_sugg(cx, iterator, pat),
 +                                Applicability::Unspecified,
 +                            );
 +                        }
 +                    };
 +                });
 +            },
 +            NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
 +        }
 +    }
 +}
 +
 +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);
 +    let mut iter = stmts.chain(expr).flatten();
 +    never_loop_expr_seq(&mut iter, main_loop_id)
 +}
 +
 +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 stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    match stmt.kind {
 +        StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e),
 +        StmtKind::Local(local) => local.init,
 +        StmtKind::Item(..) => None,
 +    }
 +}
 +
 +fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
 +    match expr.kind {
 +        ExprKind::Box(e)
 +        | ExprKind::Unary(_, e)
 +        | ExprKind::Cast(e, _)
 +        | ExprKind::Type(e, _)
 +        | ExprKind::Let(_, e, _)
 +        | ExprKind::Field(e, _)
 +        | ExprKind::AddrOf(_, _, e)
 +        | ExprKind::Struct(_, _, Some(e))
 +        | ExprKind::Repeat(e, _)
 +        | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
 +        ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => {
 +            never_loop_expr_all(&mut es.iter(), main_loop_id)
 +        },
 +        ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id),
 +        ExprKind::Binary(_, e1, e2)
 +        | ExprKind::Assign(e1, e2, _)
 +        | ExprKind::AssignOp(_, e1, e2)
 +        | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
 +        ExprKind::Loop(b, _, _, _) => {
 +            // Break can come from the inner loop so remove them.
 +            absorb_break(&never_loop_block(b, main_loop_id))
 +        },
 +        ExprKind::If(e, e2, e3) => {
 +            let e1 = never_loop_expr(e, main_loop_id);
 +            let e2 = never_loop_expr(e2, main_loop_id);
 +            let e3 = e3
 +                .as_ref()
 +                .map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
 +            combine_seq(e1, combine_branches(e2, e3))
 +        },
 +        ExprKind::Match(e, 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(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(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
 +            combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
 +        }),
 +        ExprKind::InlineAsm(asm) => asm
 +            .operands
 +            .iter()
 +            .map(|(o, _)| match o {
 +                InlineAsmOperand::In { expr, .. }
 +                | InlineAsmOperand::InOut { 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)
 +                },
 +                InlineAsmOperand::Const { .. } => NeverLoopResult::Otherwise,
 +            })
 +            .fold(NeverLoopResult::Otherwise, combine_both),
 +        ExprKind::Struct(_, _, None)
 +        | ExprKind::Yield(_, _)
 +        | ExprKind::Closure(_, _, _, _, _)
 +        | ExprKind::LlvmInlineAsm(_)
 +        | ExprKind::Path(_)
 +        | ExprKind::ConstBlock(_)
 +        | ExprKind::Lit(_)
 +        | ExprKind::Err => NeverLoopResult::Otherwise,
 +    }
 +}
 +
 +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 for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
 +    let pat_snippet = snippet(cx, pat.span, "_");
 +    let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified);
 +
 +    format!(
 +        "if let Some({pat}) = {iter}.next()",
 +        pat = pat_snippet,
 +        iter = iter_snippet
 +    )
 +}
index 8e1385fb83a25e89ff0b57ba8fa4abaf96f6d5f5,0000000000000000000000000000000000000000..b632af455f85545cae35806400df06686c9c9ba9
mode 100644,000000..100644
--- /dev/null
@@@ -1,201 -1,0 +1,201 @@@
-             if let IsAsync::NotAsync = header.asyncness;
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::match_function_call;
 +use clippy_utils::paths::FUTURE_FROM_GENERATOR;
 +use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::FnKind;
 +use rustc_hir::{
 +    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
 +    IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// It checks for manual implementations of `async` functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more idiomatic to use the dedicated syntax.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::future::Future;
 +    ///
 +    /// fn foo() -> impl Future<Output = i32> { async { 42 } }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// async fn foo() -> i32 { 42 }
 +    /// ```
 +    pub MANUAL_ASYNC_FN,
 +    style,
 +    "manual implementations of `async` functions can be simplified using the dedicated syntax"
 +}
 +
 +declare_lint_pass!(ManualAsyncFn => [MANUAL_ASYNC_FN]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
 +    fn check_fn(
 +        &mut self,
 +        cx: &LateContext<'tcx>,
 +        kind: FnKind<'tcx>,
 +        decl: &'tcx FnDecl<'_>,
 +        body: &'tcx Body<'_>,
 +        span: Span,
 +        _: HirId,
 +    ) {
 +        if_chain! {
 +            if let Some(header) = kind.header();
-         if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind;
++            if header.asyncness == IsAsync::NotAsync;
 +            // Check that this function returns `impl Future`
 +            if let FnRetTy::Return(ret_ty) = decl.output;
 +            if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty);
 +            if let Some(output) = future_output_ty(trait_ref);
 +            if captures_all_lifetimes(decl.inputs, &output_lifetimes);
 +            // Check that the body of the function consists of one async block
 +            if let ExprKind::Block(block, _) = body.value.kind;
 +            if block.stmts.is_empty();
 +            if let Some(closure_body) = desugared_async_block(cx, block);
 +            then {
 +                let header_span = span.with_hi(ret_ty.span.hi());
 +
 +                span_lint_and_then(
 +                    cx,
 +                    MANUAL_ASYNC_FN,
 +                    header_span,
 +                    "this function can be simplified using the `async fn` syntax",
 +                    |diag| {
 +                        if_chain! {
 +                            if let Some(header_snip) = snippet_opt(cx, header_span);
 +                            if let Some(ret_pos) = position_before_rarrow(&header_snip);
 +                            if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
 +                            then {
 +                                let help = format!("make the function `async` and {}", ret_sugg);
 +                                diag.span_suggestion(
 +                                    header_span,
 +                                    &help,
 +                                    format!("async {}{}", &header_snip[..ret_pos], ret_snip),
 +                                    Applicability::MachineApplicable
 +                                );
 +
 +                                let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
 +                                diag.span_suggestion(
 +                                    block.span,
 +                                    "move the body of the async block to the enclosing function",
 +                                    body_snip.to_string(),
 +                                    Applicability::MachineApplicable
 +                                );
 +                            }
 +                        }
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn future_trait_ref<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: &'tcx Ty<'tcx>,
 +) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
 +    if_chain! {
 +        if let TyKind::OpaqueDef(item_id, bounds) = ty.kind;
 +        let item = cx.tcx.hir().item(item_id);
 +        if let ItemKind::OpaqueTy(opaque) = &item.kind;
 +        if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
 +            if let GenericBound::Trait(poly, _) = bound {
 +                Some(&poly.trait_ref)
 +            } else {
 +                None
 +            }
 +        });
 +        if trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait();
 +        then {
 +            let output_lifetimes = bounds
 +                .iter()
 +                .filter_map(|bound| {
 +                    if let GenericArg::Lifetime(lt) = bound {
 +                        Some(lt.name)
 +                    } else {
 +                        None
 +                    }
 +                })
 +                .collect();
 +
 +            return Some((trait_ref, output_lifetimes));
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
 +    if_chain! {
 +        if let Some(segment) = trait_ref.path.segments.last();
 +        if let Some(args) = segment.args;
 +        if args.bindings.len() == 1;
 +        let binding = &args.bindings[0];
 +        if binding.ident.name == sym::Output;
 +        if let TypeBindingKind::Equality{ty: output} = binding.kind;
 +        then {
 +            return Some(output)
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) -> bool {
 +    let input_lifetimes: Vec<LifetimeName> = inputs
 +        .iter()
 +        .filter_map(|ty| {
 +            if let TyKind::Rptr(lt, _) = ty.kind {
 +                Some(lt.name)
 +            } else {
 +                None
 +            }
 +        })
 +        .collect();
 +
 +    // The lint should trigger in one of these cases:
 +    // - There are no input lifetimes
 +    // - There's only one output lifetime bound using `+ '_`
 +    // - All input lifetimes are explicitly bound to the output
 +    input_lifetimes.is_empty()
 +        || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore))
 +        || input_lifetimes
 +            .iter()
 +            .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
 +}
 +
 +fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
 +    if_chain! {
 +        if let Some(block_expr) = block.expr;
 +        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
 +        if args.len() == 1;
 +        if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
 +        let closure_body = cx.tcx.hir().body(body_id);
++        if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
 +        then {
 +            return Some(closure_body);
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
 +    match output.kind {
 +        TyKind::Tup(tys) if tys.is_empty() => {
 +            let sugg = "remove the return type";
 +            Some((sugg, "".into()))
 +        },
 +        _ => {
 +            let sugg = "return the output of the future directly";
 +            snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip)))
 +        },
 +    }
 +}
index 952e250bb9e6c4564f4148b8abc0aa763b6aebb7,0000000000000000000000000000000000000000..40de9ffcd4e253d2c26ef7cc997e0969ec200bc7
mode 100644,000000..100644
--- /dev/null
@@@ -1,274 -1,0 +1,273 @@@
-     let (map_type, variant, lint) =
-         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
-             ("Option", "Some", OPTION_MAP_UNIT_FN)
-         } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) {
-             ("Result", "Ok", RESULT_MAP_UNIT_FN)
-         } else {
-             return;
-         };
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{iter_input_pats, method_chain_args};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, Ty};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `option.map(f)` where f is a function
 +    /// or closure that returns the unit type `()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more clearly with
 +    /// an if let statement
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn do_stuff() -> Option<String> { Some(String::new()) }
 +    /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) }
 +    /// # fn format_msg(foo: String) -> String { String::new() }
 +    /// let x: Option<String> = do_stuff();
 +    /// x.map(log_err_msg);
 +    /// # let x: Option<String> = do_stuff();
 +    /// x.map(|msg| log_err_msg(format_msg(msg)));
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// # fn do_stuff() -> Option<String> { Some(String::new()) }
 +    /// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) }
 +    /// # fn format_msg(foo: String) -> String { String::new() }
 +    /// let x: Option<String> = do_stuff();
 +    /// if let Some(msg) = x {
 +    ///     log_err_msg(msg);
 +    /// }
 +    ///
 +    /// # let x: Option<String> = do_stuff();
 +    /// if let Some(msg) = x {
 +    ///     log_err_msg(format_msg(msg));
 +    /// }
 +    /// ```
 +    pub OPTION_MAP_UNIT_FN,
 +    complexity,
 +    "using `option.map(f)`, where `f` is a function or closure that returns `()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `result.map(f)` where f is a function
 +    /// or closure that returns the unit type `()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more clearly with
 +    /// an if let statement
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) }
 +    /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) }
 +    /// # fn format_msg(foo: String) -> String { String::new() }
 +    /// let x: Result<String, String> = do_stuff();
 +    /// x.map(log_err_msg);
 +    /// # let x: Result<String, String> = do_stuff();
 +    /// x.map(|msg| log_err_msg(format_msg(msg)));
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// # fn do_stuff() -> Result<String, String> { Ok(String::new()) }
 +    /// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) }
 +    /// # fn format_msg(foo: String) -> String { String::new() }
 +    /// let x: Result<String, String> = do_stuff();
 +    /// if let Ok(msg) = x {
 +    ///     log_err_msg(msg);
 +    /// };
 +    /// # let x: Result<String, String> = do_stuff();
 +    /// if let Ok(msg) = x {
 +    ///     log_err_msg(format_msg(msg));
 +    /// };
 +    /// ```
 +    pub RESULT_MAP_UNIT_FN,
 +    complexity,
 +    "using `result.map(f)`, where `f` is a function or closure that returns `()`"
 +}
 +
 +declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
 +
 +fn is_unit_type(ty: Ty<'_>) -> bool {
 +    match ty.kind() {
 +        ty::Tuple(slice) => slice.is_empty(),
 +        ty::Never => true,
 +        _ => false,
 +    }
 +}
 +
 +fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 +    let ty = cx.typeck_results().expr_ty(expr);
 +
 +    if let ty::FnDef(id, _) = *ty.kind() {
 +        if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
 +            return is_unit_type(fn_type.output());
 +        }
 +    }
 +    false
 +}
 +
 +fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 +    is_unit_type(cx.typeck_results().expr_ty(expr))
 +}
 +
 +/// The expression inside a closure may or may not have surrounding braces and
 +/// semicolons, which causes problems when generating a suggestion. Given an
 +/// expression that evaluates to '()' or '!', recursively remove useless braces
 +/// and semi-colons until is suitable for including in the suggestion template
 +fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<Span> {
 +    if !is_unit_expression(cx, expr) {
 +        return None;
 +    }
 +
 +    match expr.kind {
 +        hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _, _) => {
 +            // Calls can't be reduced any more
 +            Some(expr.span)
 +        },
 +        hir::ExprKind::Block(block, _) => {
 +            match (block.stmts, block.expr.as_ref()) {
 +                (&[], Some(inner_expr)) => {
 +                    // If block only contains an expression,
 +                    // reduce `{ X }` to `X`
 +                    reduce_unit_expression(cx, inner_expr)
 +                },
 +                (&[ref inner_stmt], None) => {
 +                    // If block only contains statements,
 +                    // reduce `{ X; }` to `X` or `X;`
 +                    match inner_stmt.kind {
 +                        hir::StmtKind::Local(local) => Some(local.span),
 +                        hir::StmtKind::Expr(e) => Some(e.span),
 +                        hir::StmtKind::Semi(..) => Some(inner_stmt.span),
 +                        hir::StmtKind::Item(..) => None,
 +                    }
 +                },
 +                _ => {
 +                    // For closures that contain multiple statements
 +                    // it's difficult to get a correct suggestion span
 +                    // for all cases (multi-line closures specifically)
 +                    //
 +                    // We do not attempt to build a suggestion for those right now.
 +                    None
 +                },
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn unit_closure<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
 +    if_chain! {
 +        if let hir::ExprKind::Closure(_, decl, inner_expr_id, _, _) = expr.kind;
 +        let body = cx.tcx.hir().body(inner_expr_id);
 +        let body_expr = &body.value;
 +        if decl.inputs.len() == 1;
 +        if is_unit_expression(cx, body_expr);
 +        if let Some(binding) = iter_input_pats(decl, body).next();
 +        then {
 +            return Some((binding, body_expr));
 +        }
 +    }
 +    None
 +}
 +
 +/// Builds a name for the let binding variable (`var_arg`)
 +///
 +/// `x.field` => `x_field`
 +/// `y` => `_y`
 +///
 +/// Anything else will return `a`.
 +fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
 +    match &var_arg.kind {
 +        hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
 +        hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
 +        _ => "a".to_string(),
 +    }
 +}
 +
 +#[must_use]
 +fn suggestion_msg(function_type: &str, map_type: &str) -> String {
 +    format!(
 +        "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`",
 +        map_type, function_type
 +    )
 +}
 +
 +fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
 +    let var_arg = &map_args[0];
 +
++    let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
++        ("Option", "Some", OPTION_MAP_UNIT_FN)
++    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) {
++        ("Result", "Ok", RESULT_MAP_UNIT_FN)
++    } else {
++        return;
++    };
 +    let fn_arg = &map_args[1];
 +
 +    if is_unit_function(cx, fn_arg) {
 +        let msg = suggestion_msg("function", map_type);
 +        let suggestion = format!(
 +            "if let {0}({binding}) = {1} {{ {2}({binding}) }}",
 +            variant,
 +            snippet(cx, var_arg.span, "_"),
 +            snippet(cx, fn_arg.span, "_"),
 +            binding = let_binding_name(cx, var_arg)
 +        );
 +
 +        span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
 +            diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::MachineApplicable);
 +        });
 +    } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
 +        let msg = suggestion_msg("closure", map_type);
 +
 +        span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
 +            if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
 +                let suggestion = format!(
 +                    "if let {0}({1}) = {2} {{ {3} }}",
 +                    variant,
 +                    snippet(cx, binding.pat.span, "_"),
 +                    snippet(cx, var_arg.span, "_"),
 +                    snippet(cx, reduced_expr_span, "_")
 +                );
 +                diag.span_suggestion(
 +                    stmt.span,
 +                    "try this",
 +                    suggestion,
 +                    Applicability::MachineApplicable, // snippet
 +                );
 +            } else {
 +                let suggestion = format!(
 +                    "if let {0}({1}) = {2} {{ ... }}",
 +                    variant,
 +                    snippet(cx, binding.pat.span, "_"),
 +                    snippet(cx, var_arg.span, "_"),
 +                );
 +                diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::HasPlaceholders);
 +            }
 +        });
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for MapUnit {
 +    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
 +        if stmt.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let hir::StmtKind::Semi(expr) = stmt.kind {
 +            if let Some(arglists) = method_chain_args(expr, &["map"]) {
 +                lint_map_unit_fn(cx, stmt, expr, arglists[0]);
 +            }
 +        }
 +    }
 +}
index a685c1eaa2cd5e91a73248397af3a5125c8e8cf2,0000000000000000000000000000000000000000..56d4163a6b3435cf9d6d88052c6eb1bbecd3e5ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,2374 -1,0 +1,2373 @@@
-                 && !(is_type_diagnostic_item(cx, ty, sym::Option)
-                     || is_type_diagnostic_item(cx, ty, sym::Result)) =>
 +use clippy_utils::consts::{constant, miri_to_const, Constant};
 +use clippy_utils::diagnostics::{
 +    multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 +};
 +use clippy_utils::higher;
 +use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
 +use clippy_utils::visitors::is_local_used;
 +use clippy_utils::{
 +    get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild,
 +    meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
 +    remove_blocks, strip_pat_refs,
 +};
 +use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 +use core::array;
 +use core::iter::{once, ExactSizeIterator};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{Attribute, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::def::{CtorKind, DefKind, Res};
 +use rustc_hir::LangItem::{OptionNone, OptionSome};
 +use rustc_hir::{
 +    self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
 +    Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
 +};
 +use rustc_hir::{HirIdMap, HirIdSet};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, Ty, TyS, VariantDef};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::sym;
 +use std::cmp::Ordering;
 +use std::collections::hash_map::Entry;
 +use std::iter;
 +use std::ops::Bound;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches with a single arm where an `if let`
 +    /// will usually suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn bar(stool: &str) {}
 +    /// # let x = Some("abc");
 +    /// // Bad
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => (),
 +    /// }
 +    ///
 +    /// // Good
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH,
 +    style,
 +    "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches with two arms where an `if let else` will
 +    /// usually suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// ### Known problems
 +    /// Personal style preferences may differ.
 +    ///
 +    /// ### Example
 +    /// Using `match`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => bar(&other_ref),
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `if let` with `else`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// } else {
 +    ///     bar(&other_ref);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH_ELSE,
 +    pedantic,
 +    "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches where all arms match a reference,
 +    /// suggesting to remove the reference and deref the matched expression
 +    /// instead. It also checks for `if let &foo = bar` blocks.
 +    ///
 +    /// ### Why is this bad?
 +    /// It just makes the code less readable. That reference
 +    /// destructuring adds nothing to the code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// match x {
 +    ///     &A(ref y) => foo(y),
 +    ///     &B => bar(),
 +    ///     _ => frob(&x),
 +    /// }
 +    ///
 +    /// // Good
 +    /// match *x {
 +    ///     A(ref y) => foo(y),
 +    ///     B => bar(),
 +    ///     _ => frob(x),
 +    /// }
 +    /// ```
 +    pub MATCH_REF_PATS,
 +    style,
 +    "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches where match expression is a `bool`. It
 +    /// suggests to replace the expression with an `if...else` block.
 +    ///
 +    /// ### Why is this bad?
 +    /// It makes the code less readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// match condition {
 +    ///     true => foo(),
 +    ///     false => bar(),
 +    /// }
 +    /// ```
 +    /// Use if/else instead:
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// if condition {
 +    ///     foo();
 +    /// } else {
 +    ///     bar();
 +    /// }
 +    /// ```
 +    pub MATCH_BOOL,
 +    pedantic,
 +    "a `match` on a boolean expression instead of an `if..else` block"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for overlapping match arms.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is likely to be an error and if not, makes the code
 +    /// less obvious.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 5;
 +    /// match x {
 +    ///     1..=10 => println!("1 ... 10"),
 +    ///     5..=15 => println!("5 ... 15"),
 +    ///     _ => (),
 +    /// }
 +    /// ```
 +    pub MATCH_OVERLAPPING_ARM,
 +    style,
 +    "a `match` with overlapping arms"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for arm which matches all errors with `Err(_)`
 +    /// and take drastic actions like `panic!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is generally a bad practice, similar to
 +    /// catching all exceptions in java with `catch(Exception)`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: Result<i32, &str> = Ok(3);
 +    /// match x {
 +    ///     Ok(_) => println!("ok"),
 +    ///     Err(_) => panic!("err"),
 +    /// }
 +    /// ```
 +    pub MATCH_WILD_ERR_ARM,
 +    pedantic,
 +    "a `match` with `Err(_)` arm and take drastic actions"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for match which is used to add a reference to an
 +    /// `Option` value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `as_ref()` or `as_mut()` instead is shorter.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: Option<()> = None;
 +    ///
 +    /// // Bad
 +    /// let r: Option<&()> = match x {
 +    ///     None => None,
 +    ///     Some(ref v) => Some(v),
 +    /// };
 +    ///
 +    /// // Good
 +    /// let r: Option<&()> = x.as_ref();
 +    /// ```
 +    pub MATCH_AS_REF,
 +    complexity,
 +    "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard enum matches using `_`.
 +    ///
 +    /// ### Why is this bad?
 +    /// New enum variants added by library updates can be missed.
 +    ///
 +    /// ### Known problems
 +    /// Suggested replacements may be incorrect if guards exhaustively cover some
 +    /// variants, and also may not use correct path to enum if it's not present in the current scope.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # enum Foo { A(usize), B(usize) }
 +    /// # let x = Foo::B(1);
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     Foo::B(_) => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_ENUM_MATCH_ARM,
 +    restriction,
 +    "a wildcard enum match arm using `_`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard enum matches for a single variant.
 +    ///
 +    /// ### Why is this bad?
 +    /// New enum variants added by library updates can be missed.
 +    ///
 +    /// ### Known problems
 +    /// Suggested replacements may not use correct path to enum
 +    /// if it's not present in the current scope.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # enum Foo { A, B, C }
 +    /// # let x = Foo::B;
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     Foo::C => {},
 +    /// }
 +    /// ```
 +    pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    pedantic,
 +    "a wildcard enum match for a single variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard pattern used with others patterns in same match arm.
 +    ///
 +    /// ### Why is this bad?
 +    /// Wildcard pattern already covers any other pattern as it will match anyway.
 +    /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     "bar" | _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_IN_OR_PATTERNS,
 +    complexity,
 +    "a wildcard pattern used with others patterns in same match arm"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches being used to destructure a single-variant enum
 +    /// or tuple struct where a `let` will suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `let` doesn't nest, whereas a `match` does.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    ///
 +    /// let data = match wrapper {
 +    ///     Wrapper::Data(i) => i,
 +    /// };
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    /// let Wrapper::Data(data) = wrapper;
 +    /// ```
 +    pub INFALLIBLE_DESTRUCTURING_MATCH,
 +    style,
 +    "a `match` statement with a single infallible arm instead of a `let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for useless match that binds to only one value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability and needless complexity.
 +    ///
 +    /// ### Known problems
 +    ///  Suggested replacements may be incorrect when `match`
 +    /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = 1;
 +    /// # let b = 2;
 +    ///
 +    /// // Bad
 +    /// match (a, b) {
 +    ///     (c, d) => {
 +    ///         // useless match
 +    ///     }
 +    /// }
 +    ///
 +    /// // Good
 +    /// let (c, d) = (a, b);
 +    /// ```
 +    pub MATCH_SINGLE_BINDING,
 +    complexity,
 +    "a match with a single binding instead of using `let` statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
 +    ///
 +    /// ### Why is this bad?
 +    /// Correctness and readability. It's like having a wildcard pattern after
 +    /// matching all enum variants explicitly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct A { a: i32 }
 +    /// let a = A { a: 5 };
 +    ///
 +    /// // Bad
 +    /// match a {
 +    ///     A { a: 5, .. } => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match a {
 +    ///     A { a: 5 } => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    restriction,
 +    "a match on a struct that binds all fields but still uses the wildcard pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lint for redundant pattern matching over `Result`, `Option`,
 +    /// `std::task::Poll` or `std::net::IpAddr`
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more concise and clear to just use the proper
 +    /// utility function
 +    ///
 +    /// ### Known problems
 +    /// This will change the drop order for the matched type. Both `if let` and
 +    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
 +    /// value before entering the block. For most types this change will not matter, but for a few
 +    /// types this will not be an acceptable change (e.g. locks). See the
 +    /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
 +    /// drop order.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if let Ok(_) = Ok::<i32, i32>(42) {}
 +    /// if let Err(_) = Err::<i32, i32>(42) {}
 +    /// if let None = None::<()> {}
 +    /// if let Some(_) = Some(42) {}
 +    /// if let Poll::Pending = Poll::Pending::<()> {}
 +    /// if let Poll::Ready(_) = Poll::Ready(42) {}
 +    /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
 +    /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
 +    /// match Ok::<i32, i32>(42) {
 +    ///     Ok(_) => true,
 +    ///     Err(_) => false,
 +    /// };
 +    /// ```
 +    ///
 +    /// The more idiomatic use would be:
 +    ///
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if Ok::<i32, i32>(42).is_ok() {}
 +    /// if Err::<i32, i32>(42).is_err() {}
 +    /// if None::<()>.is_none() {}
 +    /// if Some(42).is_some() {}
 +    /// if Poll::Pending::<()>.is_pending() {}
 +    /// if Poll::Ready(42).is_ready() {}
 +    /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
 +    /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
 +    /// Ok::<i32, i32>(42).is_ok();
 +    /// ```
 +    pub REDUNDANT_PATTERN_MATCHING,
 +    style,
 +    "use the proper utility function avoiding an `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `match`  or `if let` expressions producing a
 +    /// `bool` that could be written using `matches!`
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability and needless complexity.
 +    ///
 +    /// ### Known problems
 +    /// This lint falsely triggers, if there are arms with
 +    /// `cfg` attributes that remove an arm evaluating to `false`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = Some(5);
 +    ///
 +    /// // Bad
 +    /// let a = match x {
 +    ///     Some(0) => true,
 +    ///     _ => false,
 +    /// };
 +    ///
 +    /// let a = if let Some(0) = x {
 +    ///     true
 +    /// } else {
 +    ///     false
 +    /// };
 +    ///
 +    /// // Good
 +    /// let a = matches!(x, Some(0));
 +    /// ```
 +    pub MATCH_LIKE_MATCHES_MACRO,
 +    style,
 +    "a match that could be written with the matches! macro"
 +}
 +
 +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"
 +}
 +
 +#[derive(Default)]
 +pub struct Matches {
 +    msrv: Option<RustcVersion>,
 +    infallible_destructuring_match_linted: bool,
 +}
 +
 +impl Matches {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            msrv,
 +            ..Matches::default()
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(Matches => [
 +    SINGLE_MATCH,
 +    MATCH_REF_PATS,
 +    MATCH_BOOL,
 +    SINGLE_MATCH_ELSE,
 +    MATCH_OVERLAPPING_ARM,
 +    MATCH_WILD_ERR_ARM,
 +    MATCH_AS_REF,
 +    WILDCARD_ENUM_MATCH_ARM,
 +    MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    WILDCARD_IN_OR_PATTERNS,
 +    MATCH_SINGLE_BINDING,
 +    INFALLIBLE_DESTRUCTURING_MATCH,
 +    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    REDUNDANT_PATTERN_MATCHING,
 +    MATCH_LIKE_MATCHES_MACRO,
 +    MATCH_SAME_ARMS,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Matches {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
 +            return;
 +        }
 +
 +        redundant_pattern_match::check(cx, expr);
 +
 +        if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
 +            if !check_match_like_matches(cx, expr) {
 +                lint_match_arms(cx, expr);
 +            }
 +        } else {
 +            lint_match_arms(cx, expr);
 +        }
 +
 +        if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
 +            check_single_match(cx, ex, arms, expr);
 +            check_match_bool(cx, ex, arms, expr);
 +            check_overlapping_arms(cx, ex, arms);
 +            check_wild_err_arm(cx, ex, arms);
 +            check_wild_enum_match(cx, ex, arms);
 +            check_match_as_ref(cx, ex, arms, expr);
 +            check_wild_in_or_pats(cx, arms);
 +
 +            if self.infallible_destructuring_match_linted {
 +                self.infallible_destructuring_match_linted = false;
 +            } else {
 +                check_match_single_binding(cx, ex, arms, expr);
 +            }
 +        }
 +        if let ExprKind::Match(ex, arms, _) = expr.kind {
 +            check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
 +        }
 +        if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
 +            check_match_ref_pats(cx, let_expr, once(let_pat), expr);
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), local.span);
 +            if !in_macro(local.span);
 +            if let Some(expr) = local.init;
 +            if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
 +            if arms.len() == 1 && arms[0].guard.is_none();
 +            if let PatKind::TupleStruct(
 +                QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
 +            if args.len() == 1;
 +            if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
 +            let body = remove_blocks(arms[0].body);
 +            if path_to_local_id(body, arg);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                self.infallible_destructuring_match_linted = true;
 +                span_lint_and_sugg(
 +                    cx,
 +                    INFALLIBLE_DESTRUCTURING_MATCH,
 +                    local.span,
 +                    "you seem to be trying to use `match` to destructure a single infallible pattern. \
 +                    Consider using `let`",
 +                    "try this",
 +                    format!(
 +                        "let {}({}) = {};",
 +                        snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, target.span, "..", &mut applicability),
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), pat.span);
 +            if !in_macro(pat.span);
 +            if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
 +            if let Some(def_id) = path.res.opt_def_id();
 +            let ty = cx.tcx.type_of(def_id);
 +            if let ty::Adt(def, _) = ty.kind();
 +            if def.is_struct() || def.is_union();
 +            if fields.len() == def.non_enum_variant().fields.len();
 +
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +                    pat.span,
 +                    "unnecessary use of `..` pattern in struct binding. All fields were already bound",
 +                    None,
 +                    "consider removing `..` from this binding",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[rustfmt::skip]
 +fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        if in_macro(expr.span) {
 +            // Don't lint match expressions present in
 +            // macro_rules! block
 +            return;
 +        }
 +        if let PatKind::Or(..) = arms[0].pat.kind {
 +            // don't lint for or patterns for now, this makes
 +            // the lint noisy in unnecessary situations
 +            return;
 +        }
 +        let els = arms[1].body;
 +        let els = if is_unit_expr(remove_blocks(els)) {
 +            None
 +        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
 +            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
 +                // single statement/expr "else" block, don't lint
 +                return;
 +            }
 +            // block with 2+ statements or 1 expr and 1+ statement
 +            Some(els)
 +        } else {
 +            // not a block, don't lint
 +            return;
 +        };
 +
 +        let ty = cx.typeck_results().expr_ty(ex);
 +        if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
 +            check_single_match_single_pattern(cx, ex, arms, expr, els);
 +            check_single_match_opt_like(cx, ex, arms, expr, ty, els);
 +        }
 +    }
 +}
 +
 +fn check_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    if is_wild(arms[1].pat) {
 +        report_single_match_single_pattern(cx, ex, arms, expr, els);
 +    }
 +}
 +
 +fn report_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
 +    let els_str = els.map_or(String::new(), |els| {
 +        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
 +    });
 +
 +    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
 +    let (msg, sugg) = if_chain! {
 +        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
 +        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
 +        if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
 +        if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
 +        if ty.is_integral() || ty.is_char() || ty.is_str()
 +            || (implements_trait(cx, ty, spe_trait_id, &[])
 +                && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
 +        then {
 +            // scrutinee derives PartialEq and the pattern is a constant.
 +            let pat_ref_count = match pat.kind {
 +                // string literals are already a reference.
 +                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
 +                _ => pat_ref_count,
 +            };
 +            // References are only implicitly added to the pattern, so no overflow here.
 +            // e.g. will work: match &Some(_) { Some(_) => () }
 +            // will not: match Some(_) { &Some(_) => () }
 +            let ref_count_diff = ty_ref_count - pat_ref_count;
 +
 +            // Try to remove address of expressions first.
 +            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
 +            let ref_count_diff = ref_count_diff - removed;
 +
 +            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
 +            let sugg = format!(
 +                "if {} == {}{} {}{}",
 +                snippet(cx, ex.span, ".."),
 +                // PartialEq for different reference counts may not exist.
 +                "&".repeat(ref_count_diff),
 +                snippet(cx, arms[0].pat.span, ".."),
 +                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        } else {
 +            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
 +            let sugg = format!(
 +                "if let {} = {} {}{}",
 +                snippet(cx, arms[0].pat.span, ".."),
 +                snippet(cx, ex.span, ".."),
 +                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        }
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        lint,
 +        expr.span,
 +        msg,
 +        "try this",
 +        sugg,
 +        Applicability::HasPlaceholders,
 +    );
 +}
 +
 +fn check_single_match_opt_like(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    ty: Ty<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    // list of candidate `Enum`s we know will never get any more members
 +    let candidates = &[
 +        (&paths::COW, "Borrowed"),
 +        (&paths::COW, "Cow::Borrowed"),
 +        (&paths::COW, "Cow::Owned"),
 +        (&paths::COW, "Owned"),
 +        (&paths::OPTION, "None"),
 +        (&paths::RESULT, "Err"),
 +        (&paths::RESULT, "Ok"),
 +    ];
 +
 +    let path = match arms[1].pat.kind {
 +        PatKind::TupleStruct(ref path, inner, _) => {
 +            // Contains any non wildcard patterns (e.g., `Err(err)`)?
 +            if !inner.iter().all(is_wild) {
 +                return;
 +            }
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
 +        PatKind::Path(ref path) => {
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        _ => return,
 +    };
 +
 +    for &(ty_path, pat_path) in candidates {
 +        if path == *pat_path && match_type(cx, ty, ty_path) {
 +            report_single_match_single_pattern(cx, ex, arms, expr, els);
 +        }
 +    }
 +}
 +
 +fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    // Type of expression is `bool`.
 +    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
 +        span_lint_and_then(
 +            cx,
 +            MATCH_BOOL,
 +            expr.span,
 +            "you seem to be trying to match on a boolean expression",
 +            move |diag| {
 +                if arms.len() == 2 {
 +                    // no guards
 +                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
 +                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
 +                            match lit.node {
 +                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
 +                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
 +                                _ => None,
 +                            }
 +                        } else {
 +                            None
 +                        }
 +                    } else {
 +                        None
 +                    };
 +
 +                    if let Some((true_expr, false_expr)) = exprs {
 +                        let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
 +                            (false, false) => Some(format!(
 +                                "if {} {} else {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
 +                                expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (false, true) => Some(format!(
 +                                "if {} {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (true, false) => {
 +                                let test = Sugg::hir(cx, ex, "..");
 +                                Some(format!(
 +                                    "if {} {}",
 +                                    !test,
 +                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                                ))
 +                            },
 +                            (true, true) => None,
 +                        };
 +
 +                        if let Some(sugg) = sugg {
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "consider using an `if`/`else` expression",
 +                                sugg,
 +                                Applicability::HasPlaceholders,
 +                            );
 +                        }
 +                    }
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
 +    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
 +        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
 +        let type_ranges = type_ranges(&ranges);
 +        if !type_ranges.is_empty() {
 +            if let Some((start, end)) = overlapping(&type_ranges) {
 +                span_lint_and_note(
 +                    cx,
 +                    MATCH_OVERLAPPING_ARM,
 +                    start.span,
 +                    "some ranges overlap",
 +                    Some(end.span),
 +                    "overlaps with this",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
 +    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
 +    if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
 +        for arm in arms {
 +            if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
 +                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
 +                if path_str == "Err" {
 +                    let mut matching_wild = inner.iter().any(is_wild);
 +                    let mut ident_bind_name = String::from("_");
 +                    if !matching_wild {
 +                        // Looking for unused bindings (i.e.: `_e`)
 +                        for pat in inner.iter() {
 +                            if let PatKind::Binding(_, id, ident, None) = pat.kind {
 +                                if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
 +                                    ident_bind_name = (&ident.name.as_str()).to_string();
 +                                    matching_wild = true;
 +                                }
 +                            }
 +                        }
 +                    }
 +                    if_chain! {
 +                        if matching_wild;
 +                        if let ExprKind::Block(block, _) = arm.body.kind;
 +                        if is_panic_block(block);
 +                        then {
 +                            // `Err(_)` or `Err(_e)` arm with `panic!` found
 +                            span_lint_and_note(cx,
 +                                MATCH_WILD_ERR_ARM,
 +                                arm.pat.span,
 +                                &format!("`Err({})` matches all errors", &ident_bind_name),
 +                                None,
 +                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +enum CommonPrefixSearcher<'a> {
 +    None,
 +    Path(&'a [PathSegment<'a>]),
 +    Mixed,
 +}
 +impl CommonPrefixSearcher<'a> {
 +    fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
 +        match path {
 +            [path @ .., _] => self.with_prefix(path),
 +            [] => (),
 +        }
 +    }
 +
 +    fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
 +        match self {
 +            Self::None => *self = Self::Path(path),
 +            Self::Path(self_path)
 +                if path
 +                    .iter()
 +                    .map(|p| p.ident.name)
 +                    .eq(self_path.iter().map(|p| p.ident.name)) => {},
 +            Self::Path(_) => *self = Self::Mixed,
 +            Self::Mixed => (),
 +        }
 +    }
 +}
 +
 +fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
 +    let attrs = cx.tcx.get_attrs(variant_def.def_id);
 +    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 +    let ty = cx.typeck_results().expr_ty(ex).peel_refs();
 +    let adt_def = match ty.kind() {
 +        ty::Adt(adt_def, _)
 +            if adt_def.is_enum()
++                && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) =>
 +        {
 +            adt_def
 +        },
 +        _ => return,
 +    };
 +
 +    // First pass - check for violation, but don't do much book-keeping because this is hopefully
 +    // the uncommon case, and the book-keeping is slightly expensive.
 +    let mut wildcard_span = None;
 +    let mut wildcard_ident = None;
 +    let mut has_non_wild = false;
 +    for arm in arms {
 +        match peel_hir_pat_refs(arm.pat).0.kind {
 +            PatKind::Wild => wildcard_span = Some(arm.pat.span),
 +            PatKind::Binding(_, _, ident, None) => {
 +                wildcard_span = Some(arm.pat.span);
 +                wildcard_ident = Some(ident);
 +            },
 +            _ => has_non_wild = true,
 +        }
 +    }
 +    let wildcard_span = match wildcard_span {
 +        Some(x) if has_non_wild => x,
 +        _ => return,
 +    };
 +
 +    // Accumulate the variants which should be put in place of the wildcard because they're not
 +    // already covered.
 +    let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
 +    let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
 +
 +    let mut path_prefix = CommonPrefixSearcher::None;
 +    for arm in arms {
 +        // Guards mean that this case probably isn't exhaustively covered. Technically
 +        // this is incorrect, as we should really check whether each variant is exhaustively
 +        // covered by the set of guards that cover it, but that's really hard to do.
 +        recurse_or_patterns(arm.pat, |pat| {
 +            let path = match &peel_hir_pat_refs(pat).0.kind {
 +                PatKind::Path(path) => {
 +                    #[allow(clippy::match_same_arms)]
 +                    let id = match cx.qpath_res(path, pat.hir_id) {
 +                        Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
 +                        Res::Def(_, id) => id,
 +                        _ => return,
 +                    };
 +                    if arm.guard.is_none() {
 +                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
 +                    }
 +                    path
 +                },
 +                PatKind::TupleStruct(path, patterns, ..) => {
 +                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
 +                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
 +                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
 +                        }
 +                    }
 +                    path
 +                },
 +                PatKind::Struct(path, patterns, ..) => {
 +                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
 +                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
 +                            missing_variants.retain(|e| e.def_id != id);
 +                        }
 +                    }
 +                    path
 +                },
 +                _ => return,
 +            };
 +            match path {
 +                QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
 +                QPath::TypeRelative(
 +                    hir::Ty {
 +                        kind: TyKind::Path(QPath::Resolved(_, path)),
 +                        ..
 +                    },
 +                    _,
 +                ) => path_prefix.with_prefix(path.segments),
 +                _ => (),
 +            }
 +        });
 +    }
 +
 +    let format_suggestion = |variant: &VariantDef| {
 +        format!(
 +            "{}{}{}{}",
 +            if let Some(ident) = wildcard_ident {
 +                format!("{} @ ", ident.name)
 +            } else {
 +                String::new()
 +            },
 +            if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
 +                let mut s = String::new();
 +                for seg in path_prefix {
 +                    s.push_str(&seg.ident.as_str());
 +                    s.push_str("::");
 +                }
 +                s
 +            } else {
 +                let mut s = cx.tcx.def_path_str(adt_def.did);
 +                s.push_str("::");
 +                s
 +            },
 +            variant.ident.name,
 +            match variant.ctor_kind {
 +                CtorKind::Fn if variant.fields.len() == 1 => "(_)",
 +                CtorKind::Fn => "(..)",
 +                CtorKind::Const => "",
 +                CtorKind::Fictive => "{ .. }",
 +            }
 +        )
 +    };
 +
 +    match missing_variants.as_slice() {
 +        [] => (),
 +        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
 +            cx,
 +            MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +            wildcard_span,
 +            "wildcard matches only a single variant and will also match any future added variants",
 +            "try this",
 +            format_suggestion(x),
 +            Applicability::MaybeIncorrect,
 +        ),
 +        variants => {
 +            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
 +            let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
 +                suggestions.push("_".into());
 +                "wildcard matches known variants and will also match future added variants"
 +            } else {
 +                "wildcard match will also match any future added variants"
 +            };
 +
 +            span_lint_and_sugg(
 +                cx,
 +                WILDCARD_ENUM_MATCH_ARM,
 +                wildcard_span,
 +                message,
 +                "try this",
 +                suggestions.join(" | "),
 +                Applicability::MaybeIncorrect,
 +            );
 +        },
 +    };
 +}
 +
 +// If the block contains only a `panic!` macro (as expression or statement)
 +fn is_panic_block(block: &Block<'_>) -> bool {
 +    match (&block.expr, block.stmts.len(), block.stmts.first()) {
 +        (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
 +        (&None, 1, Some(stmt)) => {
 +            is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
 +        },
 +        _ => false,
 +    }
 +}
 +
 +fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
 +where
 +    'b: 'a,
 +    I: Clone + Iterator<Item = &'a Pat<'b>>,
 +{
 +    if !has_only_ref_pats(pats.clone()) {
 +        return;
 +    }
 +
 +    let (first_sugg, msg, title);
 +    let span = ex.span.source_callsite();
 +    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
 +        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
 +        msg = "try";
 +        title = "you don't need to add `&` to both the expression and the patterns";
 +    } else {
 +        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
 +        msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
 +        title = "you don't need to add `&` to all patterns";
 +    }
 +
 +    let remaining_suggs = pats.filter_map(|pat| {
 +        if let PatKind::Ref(refp, _) = pat.kind {
 +            Some((pat.span, snippet(cx, refp.span, "..").to_string()))
 +        } else {
 +            None
 +        }
 +    });
 +
 +    span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
 +        if !expr.span.from_expansion() {
 +            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
 +        }
 +    });
 +}
 +
 +fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
 +            is_ref_some_arm(cx, &arms[1])
 +        } else if is_none_arm(cx, &arms[1]) {
 +            is_ref_some_arm(cx, &arms[0])
 +        } else {
 +            None
 +        };
 +        if let Some(rb) = arm_ref {
 +            let suggestion = if rb == BindingAnnotation::Ref {
 +                "as_ref"
 +            } else {
 +                "as_mut"
 +            };
 +
 +            let output_ty = cx.typeck_results().expr_ty(expr);
 +            let input_ty = cx.typeck_results().expr_ty(ex);
 +
 +            let cast = if_chain! {
 +                if let ty::Adt(_, substs) = input_ty.kind();
 +                let input_ty = substs.type_at(0);
 +                if let ty::Adt(_, substs) = output_ty.kind();
 +                let output_ty = substs.type_at(0);
 +                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
 +                if input_ty != output_ty;
 +                then {
 +                    ".map(|x| x as _)"
 +                } else {
 +                    ""
 +                }
 +            };
 +
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_AS_REF,
 +                expr.span,
 +                &format!("use `{}()` instead", suggestion),
 +                "try this",
 +                format!(
 +                    "{}.{}(){}",
 +                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
 +                    suggestion,
 +                    cast,
 +                ),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
 +    for arm in arms {
 +        if let PatKind::Or(fields) = arm.pat.kind {
 +            // look for multiple fields in this arm that contains at least one Wild pattern
 +            if fields.len() > 1 && fields.iter().any(is_wild) {
 +                span_lint_and_help(
 +                    cx,
 +                    WILDCARD_IN_OR_PATTERNS,
 +                    arm.pat.span,
 +                    "wildcard pattern covers any other pattern as it will match anyway",
 +                    None,
 +                    "consider handling `_` separately",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
 +fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +    if let Some(higher::IfLet {
 +        let_pat,
 +        let_expr,
 +        if_then,
 +        if_else: Some(if_else),
 +    }) = higher::IfLet::hir(cx, expr)
 +    {
 +        return find_matches_sugg(
 +            cx,
 +            let_expr,
 +            array::IntoIter::new([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
 +            expr,
 +            true,
 +        );
 +    }
 +
 +    if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind {
 +        return find_matches_sugg(
 +            cx,
 +            scrut,
 +            arms.iter().map(|arm| {
 +                (
 +                    cx.tcx.hir().attrs(arm.hir_id),
 +                    Some(arm.pat),
 +                    arm.body,
 +                    arm.guard.as_ref(),
 +                )
 +            }),
 +            expr,
 +            false,
 +        );
 +    }
 +
 +    false
 +}
 +
 +/// Lint a `match` or `if let` for replacement by `matches!`
 +fn find_matches_sugg<'a, 'b, I>(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    mut iter: I,
 +    expr: &Expr<'_>,
 +    is_if_let: bool,
 +) -> bool
 +where
 +    'b: 'a,
 +    I: Clone
 +        + DoubleEndedIterator
 +        + ExactSizeIterator
 +        + Iterator<
 +            Item = (
 +                &'a [Attribute],
 +                Option<&'a Pat<'b>>,
 +                &'a Expr<'b>,
 +                Option<&'a Guard<'b>>,
 +            ),
 +        >,
 +{
 +    if_chain! {
 +        if iter.len() >= 2;
 +        if cx.typeck_results().expr_ty(expr).is_bool();
 +        if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
 +        let iter_without_last = iter.clone();
 +        if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
 +        if let Some(b0) = find_bool_lit(&first_expr.kind, is_if_let);
 +        if let Some(b1) = find_bool_lit(&last_expr.kind, is_if_let);
 +        if b0 != b1;
 +        if first_guard.is_none() || iter.len() == 0;
 +        if first_attrs.is_empty();
 +        if iter
 +            .all(|arm| {
 +                find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
 +            });
 +        then {
 +            if let Some(last_pat) = last_pat_opt {
 +                if !is_wild(last_pat) {
 +                    return false;
 +                }
 +            }
 +
 +            // The suggestion may be incorrect, because some arms can have `cfg` attributes
 +            // evaluated into `false` and so such arms will be stripped before.
 +            let mut applicability = Applicability::MaybeIncorrect;
 +            let pat = {
 +                use itertools::Itertools as _;
 +                iter_without_last
 +                    .filter_map(|arm| {
 +                        let pat_span = arm.1?.span;
 +                        Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
 +                    })
 +                    .join(" | ")
 +            };
 +            let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
 +                format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
 +            } else {
 +                pat
 +            };
 +
 +            // strip potential borrows (#6503), but only if the type is a reference
 +            let mut ex_new = ex;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
 +                if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
 +                    ex_new = ex_inner;
 +                }
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_LIKE_MATCHES_MACRO,
 +                expr.span,
 +                &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
 +                "try this",
 +                format!(
 +                    "{}matches!({}, {})",
 +                    if b0 { "" } else { "!" },
 +                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
 +                    pat_and_guard,
 +                ),
 +                applicability,
 +            );
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Extract a `bool` or `{ bool }`
 +fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
 +    match ex {
 +        ExprKind::Lit(Spanned {
 +            node: LitKind::Bool(b), ..
 +        }) => Some(*b),
 +        ExprKind::Block(
 +            rustc_hir::Block {
 +                stmts: &[],
 +                expr: Some(exp),
 +                ..
 +            },
 +            _,
 +        ) if is_if_let => {
 +            if let ExprKind::Lit(Spanned {
 +                node: LitKind::Bool(b), ..
 +            }) = exp.kind
 +            {
 +                Some(b)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
 +        return;
 +    }
 +
 +    // HACK:
 +    // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
 +    // to prevent false positives as there is currently no better way to detect if code was excluded by
 +    // a macro. See PR #6435
 +    if_chain! {
 +        if let Some(match_snippet) = snippet_opt(cx, expr.span);
 +        if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
 +        if let Some(ex_snippet) = snippet_opt(cx, ex.span);
 +        let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
 +        if rest_snippet.contains("=>");
 +        then {
 +            // The code it self contains another thick arrow "=>"
 +            // -> Either another arm or a comment
 +            return;
 +        }
 +    }
 +
 +    let matched_vars = ex.span;
 +    let bind_names = arms[0].pat.span;
 +    let match_body = remove_blocks(arms[0].body);
 +    let mut snippet_body = if match_body.span.from_expansion() {
 +        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
 +    } else {
 +        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
 +    };
 +
 +    // Do we need to add ';' to suggestion ?
 +    match match_body.kind {
 +        ExprKind::Block(block, _) => {
 +            // macro + expr_ty(body) == ()
 +            if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +        _ => {
 +            // expr_ty(body) == ()
 +            if cx.typeck_results().expr_ty(match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +    }
 +
 +    let mut applicability = Applicability::MaybeIncorrect;
 +    match arms[0].pat.kind {
 +        PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
 +            // If this match is in a local (`let`) stmt
 +            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
 +                (
 +                    parent_let_node.span,
 +                    format!(
 +                        "let {} = {};\n{}let {} = {};",
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
 +                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
 +                        snippet_body
 +                    ),
 +                )
 +            } else {
 +                // If we are in closure, we need curly braces around suggestion
 +                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
 +                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
 +                if let Some(parent_expr) = get_parent_expr(cx, expr) {
 +                    if let ExprKind::Closure(..) = parent_expr.kind {
 +                        cbrace_end = format!("\n{}}}", indent);
 +                        // Fix body indent due to the closure
 +                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
 +                        cbrace_start = format!("{{\n{}", indent);
 +                    }
 +                }
 +                // If the parent is already an arm, and the body is another match statement,
 +                // we need curly braces around suggestion
 +                let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
 +                if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
 +                    if let ExprKind::Match(..) = arm.body.kind {
 +                        cbrace_end = format!("\n{}}}", indent);
 +                        // Fix body indent due to the match
 +                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
 +                        cbrace_start = format!("{{\n{}", indent);
 +                    }
 +                }
 +                (
 +                    expr.span,
 +                    format!(
 +                        "{}let {} = {};\n{}{}{}",
 +                        cbrace_start,
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        indent,
 +                        snippet_body,
 +                        cbrace_end
 +                    ),
 +                )
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_SINGLE_BINDING,
 +                target_span,
 +                "this match could be written as a `let` statement",
 +                "consider using `let` statement",
 +                sugg,
 +                applicability,
 +            );
 +        },
 +        PatKind::Wild => {
 +            if ex.can_have_side_effects() {
 +                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
 +                let sugg = format!(
 +                    "{};\n{}{}",
 +                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
 +                    indent,
 +                    snippet_body
 +                );
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_SINGLE_BINDING,
 +                    expr.span,
 +                    "this match could be replaced by its scrutinee and body",
 +                    "consider using the scrutinee and body instead",
 +                    sugg,
 +                    applicability,
 +                );
 +            } else {
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_SINGLE_BINDING,
 +                    expr.span,
 +                    "this match could be replaced by its body itself",
 +                    "consider using the match body instead",
 +                    snippet_body,
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        },
 +        _ => (),
 +    }
 +}
 +
 +/// Returns true if the `ex` match expression is in a local (`let`) statement
 +fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
 +    let map = &cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
 +        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
 +        then {
 +            return Some(parent_let_expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets all arms that are unbounded `PatRange`s.
 +fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
 +    arms.iter()
 +        .filter_map(|arm| {
 +            if let Arm { pat, guard: None, .. } = *arm {
 +                if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
 +                    let lhs = match lhs {
 +                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
 +                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
 +                    };
 +                    let rhs = match rhs {
 +                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
 +                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
 +                    };
 +                    let rhs = match range_end {
 +                        RangeEnd::Included => Bound::Included(rhs),
 +                        RangeEnd::Excluded => Bound::Excluded(rhs),
 +                    };
 +                    return Some(SpannedRange {
 +                        span: pat.span,
 +                        node: (lhs, rhs),
 +                    });
 +                }
 +
 +                if let PatKind::Lit(value) = pat.kind {
 +                    let value = constant(cx, cx.typeck_results(), value)?.0;
 +                    return Some(SpannedRange {
 +                        span: pat.span,
 +                        node: (value.clone(), Bound::Included(value)),
 +                    });
 +                }
 +            }
 +            None
 +        })
 +        .collect()
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct SpannedRange<T> {
 +    pub span: Span,
 +    pub node: (T, Bound<T>),
 +}
 +
 +type TypedRanges = Vec<SpannedRange<u128>>;
 +
 +/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
 +/// and other types than
 +/// `Uint` and `Int` probably don't make sense.
 +fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
 +    ranges
 +        .iter()
 +        .filter_map(|range| match range.node {
 +            (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Included(end)),
 +            }),
 +            (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Excluded(end)),
 +            }),
 +            (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Unbounded),
 +            }),
 +            _ => None,
 +        })
 +        .collect()
 +}
 +
 +// Checks if arm has the form `None => None`
 +fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +    matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
 +}
 +
 +// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
 +    if_chain! {
 +        if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
 +        if is_lang_ctor(cx, qpath, OptionSome);
 +        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
 +        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
 +        if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
 +        if let ExprKind::Path(ref some_path) = e.kind;
 +        if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
 +        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
 +        if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
 +        then {
 +            return Some(rb)
 +        }
 +    }
 +    None
 +}
 +
 +fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
 +where
 +    'b: 'a,
 +    I: Iterator<Item = &'a Pat<'b>>,
 +{
 +    let mut at_least_one_is_true = false;
 +    for opt in pats.map(|pat| match pat.kind {
 +        PatKind::Ref(..) => Some(true), // &-patterns
 +        PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
 +        _ => None,                      // any other pattern is not fine
 +    }) {
 +        if let Some(inner) = opt {
 +            if inner {
 +                at_least_one_is_true = true;
 +            }
 +        } else {
 +            return false;
 +        }
 +    }
 +    at_least_one_is_true
 +}
 +
 +pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
 +where
 +    T: Copy + Ord,
 +{
 +    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +    enum Kind<'a, T> {
 +        Start(T, &'a SpannedRange<T>),
 +        End(Bound<T>, &'a SpannedRange<T>),
 +    }
 +
 +    impl<'a, T: Copy> Kind<'a, T> {
 +        fn range(&self) -> &'a SpannedRange<T> {
 +            match *self {
 +                Kind::Start(_, r) | Kind::End(_, r) => r,
 +            }
 +        }
 +
 +        fn value(self) -> Bound<T> {
 +            match self {
 +                Kind::Start(t, _) => Bound::Included(t),
 +                Kind::End(t, _) => t,
 +            }
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> {
 +        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 +            Some(self.cmp(other))
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
 +        fn cmp(&self, other: &Self) -> Ordering {
 +            match (self.value(), other.value()) {
 +                (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
 +                // Range patterns cannot be unbounded (yet)
 +                (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
 +                (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Greater,
 +                    other => other,
 +                },
 +                (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Less,
 +                    other => other,
 +                },
 +            }
 +        }
 +    }
 +
 +    let mut values = Vec::with_capacity(2 * ranges.len());
 +
 +    for r in ranges {
 +        values.push(Kind::Start(r.node.0, r));
 +        values.push(Kind::End(r.node.1, r));
 +    }
 +
 +    values.sort();
 +
 +    for (a, b) in iter::zip(&values, values.iter().skip(1)) {
 +        match (a, b) {
 +            (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
 +                if ra.node != rb.node {
 +                    return Some((ra, rb));
 +                }
 +            },
 +            (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
 +            _ => {
 +                // skip if the range `a` is completely included into the range `b`
 +                if let Ordering::Equal | Ordering::Less = a.cmp(b) {
 +                    let kind_a = Kind::End(a.range().node.1, a.range());
 +                    let kind_b = Kind::End(b.range().node.1, b.range());
 +                    if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
 +                        return None;
 +                    }
 +                }
 +                return Some((a.range(), b.range()));
 +            },
 +        }
 +    }
 +
 +    None
 +}
 +
 +mod redundant_pattern_match {
 +    use super::REDUNDANT_PATTERN_MATCHING;
 +    use clippy_utils::diagnostics::span_lint_and_then;
 +    use clippy_utils::higher;
 +    use clippy_utils::source::{snippet, snippet_with_applicability};
 +    use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
 +    use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
 +    use if_chain::if_chain;
 +    use rustc_ast::ast::LitKind;
 +    use rustc_data_structures::fx::FxHashSet;
 +    use rustc_errors::Applicability;
 +    use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 +    use rustc_hir::{
 +        intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
 +        Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath,
 +    };
 +    use rustc_lint::LateContext;
 +    use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 +    use rustc_span::sym;
 +
 +    pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let Some(higher::IfLet {
 +            if_else,
 +            let_pat,
 +            let_expr,
 +            ..
 +        }) = higher::IfLet::hir(cx, expr)
 +        {
 +            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some());
 +        }
 +        if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind {
 +            find_sugg_for_match(cx, expr, op, arms);
 +        }
 +        if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
 +            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
 +        }
 +    }
 +
 +    /// Checks if the drop order for a type matters. Some std types implement drop solely to
 +    /// deallocate memory. For these types, and composites containing them, changing the drop order
 +    /// won't result in any observable side effects.
 +    fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +        type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 +    }
 +
 +    fn type_needs_ordered_drop_inner(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
 +        if !seen.insert(ty) {
 +            return false;
 +        }
 +        if !ty.needs_drop(cx.tcx, cx.param_env) {
 +            false
 +        } else if !cx
 +            .tcx
 +            .lang_items()
 +            .drop_trait()
 +            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
 +        {
 +            // This type doesn't implement drop, so no side effects here.
 +            // Check if any component type has any.
 +            match ty.kind() {
 +                ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
 +                ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen),
 +                ty::Adt(adt, subs) => adt
 +                    .all_fields()
 +                    .map(|f| f.ty(cx.tcx, subs))
 +                    .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
 +                _ => true,
 +            }
 +        }
 +        // Check for std types which implement drop, but only for memory allocation.
 +        else if is_type_diagnostic_item(cx, ty, sym::Vec)
 +            || is_type_lang_item(cx, ty, LangItem::OwnedBox)
 +            || is_type_diagnostic_item(cx, ty, sym::Rc)
 +            || is_type_diagnostic_item(cx, ty, sym::Arc)
 +            || is_type_diagnostic_item(cx, ty, sym::cstring_type)
 +            || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
 +            || is_type_diagnostic_item(cx, ty, sym::LinkedList)
 +            || match_type(cx, ty, &paths::WEAK_RC)
 +            || match_type(cx, ty, &paths::WEAK_ARC)
 +        {
 +            // Check all of the generic arguments.
 +            if let ty::Adt(_, subs) = ty.kind() {
 +                subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
 +            } else {
 +                true
 +            }
 +        } else {
 +            true
 +        }
 +    }
 +
 +    // Extract the generic arguments out of a type
 +    fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
 +        if_chain! {
 +            if let ty::Adt(_, subs) = ty.kind();
 +            if let Some(sub) = subs.get(index);
 +            if let GenericArgKind::Type(sub_ty) = sub.unpack();
 +            then {
 +                Some(sub_ty)
 +            } else {
 +                None
 +            }
 +        }
 +    }
 +
 +    // Checks if there are any temporaries created in the given expression for which drop order
 +    // matters.
 +    fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
 +        struct V<'a, 'tcx> {
 +            cx: &'a LateContext<'tcx>,
 +            res: bool,
 +        }
 +        impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
 +            type Map = ErasedMap<'tcx>;
 +            fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +                NestedVisitorMap::None
 +            }
 +
 +            fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 +                match expr.kind {
 +                    // Taking the reference of a value leaves a temporary
 +                    // e.g. In `&String::new()` the string is a temporary value.
 +                    // Remaining fields are temporary values
 +                    // e.g. In `(String::new(), 0).1` the string is a temporary value.
 +                    ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
 +                        if !matches!(expr.kind, ExprKind::Path(_)) {
 +                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(expr);
 +                            }
 +                        }
 +                    },
 +                    // the base type is alway taken by reference.
 +                    // e.g. In `(vec![0])[0]` the vector is a temporary value.
 +                    ExprKind::Index(base, index) => {
 +                        if !matches!(base.kind, ExprKind::Path(_)) {
 +                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(base);
 +                            }
 +                        }
 +                        self.visit_expr(index);
 +                    },
 +                    // Method calls can take self by reference.
 +                    // e.g. In `String::new().len()` the string is a temporary value.
 +                    ExprKind::MethodCall(_, _, [self_arg, args @ ..], _) => {
 +                        if !matches!(self_arg.kind, ExprKind::Path(_)) {
 +                            let self_by_ref = self
 +                                .cx
 +                                .typeck_results()
 +                                .type_dependent_def_id(expr.hir_id)
 +                                .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
 +                            if self_by_ref
 +                                && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg))
 +                            {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(self_arg);
 +                            }
 +                        }
 +                        args.iter().for_each(|arg| self.visit_expr(arg));
 +                    },
 +                    // Either explicitly drops values, or changes control flow.
 +                    ExprKind::DropTemps(_)
 +                    | ExprKind::Ret(_)
 +                    | ExprKind::Break(..)
 +                    | ExprKind::Yield(..)
 +                    | ExprKind::Block(Block { expr: None, .. }, _)
 +                    | ExprKind::Loop(..) => (),
 +
 +                    // Only consider the final expression.
 +                    ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
 +
 +                    _ => walk_expr(self, expr),
 +                }
 +            }
 +        }
 +
 +        let mut v = V { cx, res: false };
 +        v.visit_expr(expr);
 +        v.res
 +    }
 +
 +    fn find_sugg_for_if_let<'tcx>(
 +        cx: &LateContext<'tcx>,
 +        expr: &'tcx Expr<'_>,
 +        let_pat: &Pat<'_>,
 +        let_expr: &'tcx Expr<'_>,
 +        keyword: &'static str,
 +        has_else: bool,
 +    ) {
 +        // also look inside refs
 +        let mut kind = &let_pat.kind;
 +        // if we have &None for example, peel it so we can detect "if let None = x"
 +        if let PatKind::Ref(inner, _mutability) = kind {
 +            kind = &inner.kind;
 +        }
 +        let op_ty = cx.typeck_results().expr_ty(let_expr);
 +        // Determine which function should be used, and the type contained by the corresponding
 +        // variant.
 +        let (good_method, inner_ty) = match kind {
 +            PatKind::TupleStruct(ref path, [sub_pat], _) => {
 +                if let PatKind::Wild = sub_pat.kind {
 +                    if is_lang_ctor(cx, path, ResultOk) {
 +                        ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
 +                    } else if is_lang_ctor(cx, path, ResultErr) {
 +                        ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
 +                    } else if is_lang_ctor(cx, path, OptionSome) {
 +                        ("is_some()", op_ty)
 +                    } else if is_lang_ctor(cx, path, PollReady) {
 +                        ("is_ready()", op_ty)
 +                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
 +                        ("is_ipv4()", op_ty)
 +                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
 +                        ("is_ipv6()", op_ty)
 +                    } else {
 +                        return;
 +                    }
 +                } else {
 +                    return;
 +                }
 +            },
 +            PatKind::Path(ref path) => {
 +                let method = if is_lang_ctor(cx, path, OptionNone) {
 +                    "is_none()"
 +                } else if is_lang_ctor(cx, path, PollPending) {
 +                    "is_pending()"
 +                } else {
 +                    return;
 +                };
 +                // `None` and `Pending` don't have an inner type.
 +                (method, cx.tcx.types.unit)
 +            },
 +            _ => return,
 +        };
 +
 +        // If this is the last expression in a block or there is an else clause then the whole
 +        // type needs to be considered, not just the inner type of the branch being matched on.
 +        // Note the last expression in a block is dropped after all local bindings.
 +        let check_ty = if has_else
 +            || (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
 +        {
 +            op_ty
 +        } else {
 +            inner_ty
 +        };
 +
 +        // All temporaries created in the scrutinee expression are dropped at the same time as the
 +        // scrutinee would be, so they have to be considered as well.
 +        // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
 +        // for the duration if body.
 +        let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
 +
 +        // check that `while_let_on_iterator` lint does not trigger
 +        if_chain! {
 +            if keyword == "while";
 +            if let ExprKind::MethodCall(method_path, _, _, _) = let_expr.kind;
 +            if method_path.ident.name == sym::next;
 +            if is_trait_method(cx, let_expr, sym::Iterator);
 +            then {
 +                return;
 +            }
 +        }
 +
 +        let result_expr = match &let_expr.kind {
 +            ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +            _ => let_expr,
 +        };
 +        span_lint_and_then(
 +            cx,
 +            REDUNDANT_PATTERN_MATCHING,
 +            let_pat.span,
 +            &format!("redundant pattern matching, consider using `{}`", good_method),
 +            |diag| {
 +                // if/while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +                let expr_span = expr.span;
 +
 +                // if/while let ... = ... { ... }
 +                //                 ^^^
 +                let op_span = result_expr.span.source_callsite();
 +
 +                // if/while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^
 +                let span = expr_span.until(op_span.shrink_to_hi());
 +
 +                let mut app = if needs_drop {
 +                    Applicability::MaybeIncorrect
 +                } else {
 +                    Applicability::MachineApplicable
 +                };
 +                let sugg = snippet_with_applicability(cx, op_span, "_", &mut app);
 +
 +                diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
 +
 +                if needs_drop {
 +                    diag.note("this will change drop order of the result, as well as all temporaries");
 +                    diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
 +                }
 +            },
 +        );
 +    }
 +
 +    fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
 +        if arms.len() == 2 {
 +            let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 +
 +            let found_good_method = match node_pair {
 +                (
 +                    PatKind::TupleStruct(ref path_left, patterns_left, _),
 +                    PatKind::TupleStruct(ref path_right, patterns_right, _),
 +                ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
 +                    if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
 +                        find_good_method_for_match(
 +                            cx,
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::RESULT_OK,
 +                            &paths::RESULT_ERR,
 +                            "is_ok()",
 +                            "is_err()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                cx,
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::IPADDR_V4,
 +                                &paths::IPADDR_V6,
 +                                "is_ipv4()",
 +                                "is_ipv6()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
 +                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
 +                    if patterns.len() == 1 =>
 +                {
 +                    if let PatKind::Wild = patterns[0].kind {
 +                        find_good_method_for_match(
 +                            cx,
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::OPTION_SOME,
 +                            &paths::OPTION_NONE,
 +                            "is_some()",
 +                            "is_none()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                cx,
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::POLL_READY,
 +                                &paths::POLL_PENDING,
 +                                "is_ready()",
 +                                "is_pending()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                _ => None,
 +            };
 +
 +            if let Some(good_method) = found_good_method {
 +                let span = expr.span.to(op.span);
 +                let result_expr = match &op.kind {
 +                    ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +                    _ => op,
 +                };
 +                span_lint_and_then(
 +                    cx,
 +                    REDUNDANT_PATTERN_MATCHING,
 +                    expr.span,
 +                    &format!("redundant pattern matching, consider using `{}`", good_method),
 +                    |diag| {
 +                        diag.span_suggestion(
 +                            span,
 +                            "try this",
 +                            format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
 +                            Applicability::MaybeIncorrect, // snippet
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_arguments)]
 +    fn find_good_method_for_match<'a>(
 +        cx: &LateContext<'_>,
 +        arms: &[Arm<'_>],
 +        path_left: &QPath<'_>,
 +        path_right: &QPath<'_>,
 +        expected_left: &[&str],
 +        expected_right: &[&str],
 +        should_be_left: &'a str,
 +        should_be_right: &'a str,
 +    ) -> Option<&'a str> {
 +        let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
 +            && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
 +        {
 +            (&(*arms[0].body).kind, &(*arms[1].body).kind)
 +        } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
 +            && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
 +        {
 +            (&(*arms[1].body).kind, &(*arms[0].body).kind)
 +        } else {
 +            return None;
 +        };
 +
 +        match body_node_pair {
 +            (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
 +                (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
 +                (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
 +                _ => None,
 +            },
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[test]
 +fn test_overlapping() {
 +    use rustc_span::source_map::DUMMY_SP;
 +
 +    let sp = |s, e| SpannedRange {
 +        span: DUMMY_SP,
 +        node: (s, e),
 +    };
 +
 +    assert_eq!(None, overlapping::<u8>(&[]));
 +    assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
 +    assert_eq!(
 +        None,
 +        overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        None,
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(10, Bound::Included(11))
 +        ],)
 +    );
 +    assert_eq!(
 +        Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
 +        overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(6, Bound::Included(11))
 +        ],)
 +    );
 +}
 +
 +/// Implementation of `MATCH_SAME_ARMS`.
 +fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +    if let ExprKind::Match(_, 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);
 +
 +            let mut local_map: HirIdMap<HirId> = HirIdMap::default();
 +            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
 +                if_chain! {
 +                    if let Some(a_id) = path_to_local(a);
 +                    if let Some(b_id) = path_to_local(b);
 +                    let entry = match local_map.entry(a_id) {
 +                        Entry::Vacant(entry) => entry,
 +                        // check if using the same bindings as before
 +                        Entry::Occupied(entry) => return *entry.get() == b_id,
 +                    };
 +                    // the names technically don't have to match; this makes the lint more conservative
 +                    if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
 +                    if TyS::same_type(cx.typeck_results().expr_ty(a), cx.typeck_results().expr_ty(b));
 +                    if pat_contains_local(lhs.pat, a_id);
 +                    if pat_contains_local(rhs.pat, b_id);
 +                    then {
 +                        entry.insert(b_id);
 +                        true
 +                    } else {
 +                        false
 +                    }
 +                }
 +            };
 +            // 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)
 +                    .expr_fallback(eq_fallback)
 +                    .eq_expr(lhs.body, rhs.body)
 +                // these checks could be removed to allow unused bindings
 +                && bindings_eq(lhs.pat, local_map.keys().copied().collect())
 +                && bindings_eq(rhs.pat, local_map.values().copied().collect())
 +        };
 +
 +        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,))
 +                            .help("...or consider changing the match arm bodies");
 +                    }
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
 +    let mut result = false;
 +    pat.walk_short(|p| {
 +        result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
 +        !result
 +    });
 +    result
 +}
 +
 +/// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
 +fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
 +    let mut result = true;
 +    pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
 +    result && ids.is_empty()
 +}
index 2025056ac94c3365a398dfb22987be6513a47791,0000000000000000000000000000000000000000..b26d11c0d6b0d8620a77e985e0dc023e16c2bffc
mode 100644,000000..100644
--- /dev/null
@@@ -1,2468 -1,0 +1,2469 @@@
-     /// 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.
 +mod bind_instead_of_map;
 +mod bytes_nth;
 +mod chars_cmp;
 +mod chars_cmp_with_unwrap;
 +mod chars_last_cmp;
 +mod chars_last_cmp_with_unwrap;
 +mod chars_next_cmp;
 +mod chars_next_cmp_with_unwrap;
 +mod clone_on_copy;
 +mod clone_on_ref_ptr;
 +mod cloned_instead_of_copied;
 +mod expect_fun_call;
 +mod expect_used;
 +mod extend_with_drain;
 +mod filetype_is_file;
 +mod filter_map;
 +mod filter_map_identity;
 +mod filter_map_next;
 +mod filter_next;
 +mod flat_map_identity;
 +mod flat_map_option;
 +mod from_iter_instead_of_collect;
 +mod get_unwrap;
 +mod implicit_clone;
 +mod inefficient_to_string;
 +mod inspect_for_each;
 +mod into_iter_on_ref;
 +mod iter_cloned_collect;
 +mod iter_count;
 +mod iter_next_slice;
 +mod iter_nth;
 +mod iter_nth_zero;
 +mod iter_skip_next;
 +mod iterator_step_by_zero;
 +mod manual_saturating_arithmetic;
 +mod manual_split_once;
 +mod manual_str_repeat;
 +mod map_collect_result_unit;
 +mod map_flatten;
 +mod map_identity;
 +mod map_unwrap_or;
 +mod ok_expect;
 +mod option_as_ref_deref;
 +mod option_map_or_none;
 +mod option_map_unwrap_or;
 +mod or_fun_call;
 +mod search_is_some;
 +mod single_char_add_str;
 +mod single_char_insert_string;
 +mod single_char_pattern;
 +mod single_char_push_string;
 +mod skip_while_next;
 +mod string_extend_chars;
 +mod suspicious_map;
 +mod suspicious_splitn;
 +mod uninit_assumed_init;
 +mod unnecessary_filter_map;
 +mod unnecessary_fold;
 +mod unnecessary_lazy_eval;
 +mod unwrap_or_else_default;
 +mod unwrap_used;
 +mod useless_asref;
 +mod utils;
 +mod wrong_self_convention;
 +mod zst_offset;
 +
 +use bind_instead_of_map::BindInsteadOfMap;
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
 +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::def::Res;
 +use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::SymbolStr;
 +use rustc_span::{sym, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `cloned()` on an `Iterator` or `Option` where
 +    /// `copied()` could be used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `copied()` is better because it guarantees that the type being cloned
 +    /// implements `Copy`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1, 2, 3].iter().cloned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// [1, 2, 3].iter().copied();
 +    /// ```
 +    pub CLONED_INSTEAD_OF_COPIED,
 +    pedantic,
 +    "used `cloned` where `copied` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
 +    /// used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// When applicable, `filter_map()` is more clear since it shows that
 +    /// `Option` is used to produce 0 or 1 items.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    pub FLAT_MAP_OPTION,
 +    pedantic,
 +    "used `flat_map` where `filter_map` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is better to handle the `None` or `Err` case,
 +    /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
 +    /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// `result.unwrap()` will let the thread panic on `Err` values.
 +    /// Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// Even if you want to panic on errors, not all `Error`s implement good
 +    /// messages on display. Therefore, it may be beneficial to look at the places
 +    /// where they may get displayed. Activate this lint to do just that.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.unwrap();
 +    ///
 +    /// // Good
 +    /// opt.expect("more helpful message");
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.unwrap();
 +    ///
 +    /// // Good
 +    /// res.expect("more helpful message");
 +    /// ```
 +    pub UNWRAP_USED,
 +    restriction,
 +    "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.expect()` calls on `Option`s and `Result`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// Usually it is better to handle the `None` or `Err` case.
 +    /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
 +    /// this lint is `Allow` by default.
 +    ///
 +    /// `result.expect()` will let the thread panic on `Err`
 +    /// values. Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// ### Examples
 +    /// ```rust,ignore
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.expect("one");
 +    ///
 +    /// // Good
 +    /// let opt = Some(1);
 +    /// opt?;
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.expect("one");
 +    ///
 +    /// // Good
 +    /// res?;
 +    /// # Ok::<(), ()>(())
 +    /// ```
 +    pub EXPECT_USED,
 +    restriction,
 +    "using `.expect()` on `Result` or `Option`, which might be better handled"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods that should live in a trait
 +    /// implementation of a `std` trait (see [llogiq's blog
 +    /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
 +    /// information) instead of an inherent implementation.
 +    ///
 +    /// ### Why is this bad?
 +    /// Implementing the traits improve ergonomics for users of
 +    /// the code, often with very little cost. Also people seeing a `mul(...)`
 +    /// method
 +    /// may expect `*` to work equally, so you should have good reason to disappoint
 +    /// them.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn add(&self, other: &X) -> X {
 +    ///         // ..
 +    /// # X
 +    ///     }
 +    /// }
 +    /// ```
 +    pub SHOULD_IMPLEMENT_TRAIT,
 +    style,
 +    "defining a method that should be implementing a std trait"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods with certain name prefixes and which
 +    /// doesn't match how self is taken. The actual rules are:
 +    ///
 +    /// |Prefix |Postfix     |`self` taken           | `self` type  |
 +    /// |-------|------------|-----------------------|--------------|
 +    /// |`as_`  | none       |`&self` or `&mut self` | any          |
 +    /// |`from_`| none       | none                  | any          |
 +    /// |`into_`| none       |`self`                 | any          |
 +    /// |`is_`  | none       |`&self` or none        | any          |
 +    /// |`to_`  | `_mut`     |`&mut self`            | any          |
 +    /// |`to_`  | not `_mut` |`self`                 | `Copy`       |
 +    /// |`to_`  | not `_mut` |`&self`                | not `Copy`   |
 +    ///
 +    /// Note: Clippy doesn't trigger methods with `to_` prefix in:
 +    /// - Traits definition.
 +    /// Clippy can not tell if a type that implements a trait is `Copy` or not.
 +    /// - Traits implementation, when `&self` is taken.
 +    /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
 +    /// (see e.g. the `std::string::ToString` trait).
 +    ///
 +    /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
 +    ///
 +    /// Please find more info here:
 +    /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
 +    ///
 +    /// ### Why is this bad?
 +    /// Consistency breeds readability. If you follow the
 +    /// conventions, your users won't be surprised that they, e.g., need to supply a
 +    /// mutable reference to a `as_..` function.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct X;
 +    /// impl X {
 +    ///     fn as_str(self) -> &'static str {
 +    ///         // ..
 +    /// # ""
 +    ///     }
 +    /// }
 +    /// ```
 +    pub WRONG_SELF_CONVENTION,
 +    style,
 +    "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `ok().expect(..)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Because you usually call `expect()` on the `Result`
 +    /// directly to get a better error message.
 +    ///
 +    /// ### Known problems
 +    /// The error type needs to implement `Debug`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = Ok::<_, ()>(());
 +    ///
 +    /// // Bad
 +    /// x.ok().expect("why did I do this again?");
 +    ///
 +    /// // Good
 +    /// x.expect("why did I do this again?");
 +    /// ```
 +    pub OK_EXPECT,
 +    style,
 +    "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
 +    /// `Result` values.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written as `_.unwrap_or_default`, which is
 +    /// simpler and more concise.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let x = Some(1);
 +    ///
 +    /// // Bad
 +    /// x.unwrap_or_else(Default::default);
 +    /// x.unwrap_or_else(u32::default);
 +    ///
 +    /// // Good
 +    /// x.unwrap_or_default();
 +    /// ```
 +    pub UNWRAP_OR_ELSE_DEFAULT,
 +    style,
 +    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
 +    /// `result.map(_).unwrap_or_else(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written more concisely (resp.) as
 +    /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
 +    ///
 +    /// ### Known problems
 +    /// The order of the arguments is not in execution order
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let x = Some(1);
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or(0);
 +    ///
 +    /// // Good
 +    /// x.map_or(0, |a| a + 1);
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let x: Result<usize, ()> = Ok(1);
 +    /// # fn some_function(foo: ()) -> usize { 1 }
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or_else(some_function);
 +    ///
 +    /// // Good
 +    /// x.map_or_else(some_function, |a| a + 1);
 +    /// ```
 +    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()`.
 +    ///
 +    /// ### 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)`.
 +    ///
 +    /// ### 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(_)`.
 +    ///
 +    /// ### 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)`.
 +    ///
 +    /// ### 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(_)` on `Iterator` and `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.flat_map(_)`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![vec![1]];
 +    ///
 +    /// // Bad
 +    /// vec.iter().map(|x| x.iter()).flatten();
 +    ///
 +    /// // Good
 +    /// vec.iter().flat_map(|x| x.iter());
 +    /// ```
 +    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(_)` that can be written more simply
 +    /// as `filter_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `filter` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .filter(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// (0_i32..10).filter_map(|n| n.checked_add(1));
 +    /// ```
 +    pub MANUAL_FILTER_MAP,
 +    complexity,
 +    "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.find(_).map(_)` that can be written more simply
 +    /// as `find_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `find` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .find(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// (0_i32..10).find_map(|n| n.checked_add(1));
 +    /// ```
 +    pub MANUAL_FIND_MAP,
 +    complexity,
 +    "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter_map(_).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find_map(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
 +    /// ```
 +    /// Can be written as
 +    ///
 +    /// ```rust
 +    ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
 +    /// ```
 +    pub FILTER_MAP_NEXT,
 +    pedantic,
 +    "using combination of `filter_map` and `next` which can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `flat_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flat_map(|x| x);
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    pub FLAT_MAP_IDENTITY,
 +    complexity,
 +    "call to `flat_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for an iterator or string search (such as `find()`,
 +    /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as:
 +    /// * `_.any(_)`, or `_.contains(_)` for `is_some()`,
 +    /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0).is_some();
 +    ///
 +    /// let _ = "hello world".find("world").is_none();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().any(|x| *x == 0);
 +    ///
 +    /// let _ = !"hello world".contains("world");
 +    /// ```
 +    pub SEARCH_IS_SOME,
 +    complexity,
 +    "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.chars().next()` on a `str` to check
 +    /// if it starts with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.starts_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.chars().next() == Some('_') {};
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.starts_with('_') {};
 +    /// ```
 +    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.
 +    ///
 +    /// ### 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`.
 +    ///
 +    /// ### 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.
 +    ///
 +    /// ### 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.
 +    ///
 +    /// ### Example
 +    /// In an impl block:
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct NotAFoo;
 +    /// impl Foo {
 +    ///     fn new() -> NotAFoo {
 +    /// # NotAFoo
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// struct Bar(Foo);
 +    /// impl Foo {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new() -> Bar {
 +    /// # Bar(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct FooError;
 +    /// impl Foo {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Result<Foo, FooError> {
 +    /// # Ok(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Or in a trait definition:
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new();
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Self;
 +    /// }
 +    /// ```
 +    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 calling `.step_by(0)` on iterators which panics.
 +    ///
 +    /// ### Why is this bad?
 +    /// This very much looks like an oversight. Use `panic!()` instead if you
 +    /// actually intend to panic.
 +    ///
 +    /// ### Example
 +    /// ```rust,should_panic
 +    /// for x in (0..100).step_by(0) {
 +    ///     //..
 +    /// }
 +    /// ```
 +    pub ITERATOR_STEP_BY_ZERO,
 +    correctness,
 +    "using `Iterator::step_by(0)`, which will panic at runtime"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for indirect collection of populated `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// `Option` is like a collection of 0-1 things, so `flatten`
 +    /// automatically does this without suspicious-looking `unwrap` calls.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().flatten();
 +    /// ```
 +    pub OPTION_FILTER_MAP,
 +    complexity,
 +    "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `iter.nth(0)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `iter.next()` is equivalent to
 +    /// `iter.nth(0)`, as they both consume the next element,
 +    ///  but is more readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// // Bad
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().nth(0);
 +    ///
 +    /// // Good
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().next();
 +    /// ```
 +    pub ITER_NTH_ZERO,
 +    style,
 +    "replace `iter.nth(0)` with `iter.next()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.iter().nth()` (and the related
 +    /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.get()` and `.get_mut()` are more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.get(3);
 +    /// let bad_slice = &some_vec[..].get(3);
 +    /// ```
 +    pub ITER_NTH,
 +    perf,
 +    "using `.iter().nth()` on a standard library type with O(1) element access"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.skip(x).next()` on iterators.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.nth(x)` is cleaner
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().skip(3).next();
 +    /// let bad_slice = &some_vec[..].iter().skip(3).next();
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    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 occurrences where one vector gets extended instead of append
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `append` instead of `extend` is more concise and faster
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut a = vec![1, 2, 3];
 +    /// let mut b = vec![4, 5, 6];
 +    ///
 +    /// // Bad
 +    /// a.extend(b.drain(..));
 +    ///
 +    /// // Good
 +    /// a.append(&mut b);
 +    /// ```
 +    pub EXTEND_WITH_DRAIN,
 +    perf,
 +    "using vec.append(&mut vec) to move the full range of a vecor to another"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.extend(s.chars())` where s is a
 +    /// `&str` or `String`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.push_str(s)` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.extend(abc.chars());
 +    /// s.extend(def.chars());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.push_str(abc);
 +    /// s.push_str(&def);
 +    /// ```
 +    pub STRING_EXTEND_CHARS,
 +    style,
 +    "using `x.extend(s.chars())` where s is a `&str` or `String`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.cloned().collect()` on slice to
 +    /// create a `Vec`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.to_vec()` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s[..].iter().cloned().collect();
 +    /// ```
 +    /// The better use would be:
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s.to_vec();
 +    /// ```
 +    pub ITER_CLONED_COLLECT,
 +    style,
 +    "using `.cloned().collect()` on slice to create a `Vec`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.chars().last()` or
 +    /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.ends_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let name = "_";
 +    ///
 +    /// // Bad
 +    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
 +    ///
 +    /// // Good
 +    /// name.ends_with('_') || name.ends_with('-');
 +    /// ```
 +    pub CHARS_LAST_CMP,
 +    style,
 +    "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.as_ref()` or `.as_mut()` where the
 +    /// types before and after the call are the same.
 +    ///
 +    /// ### Why is this bad?
 +    /// The call is unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x.as_ref());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x);
 +    /// ```
 +    pub USELESS_ASREF,
 +    complexity,
 +    "using `as_ref` where the types before and after the call are the same"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for using `fold` when a more succinct alternative exists.
 +    /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
 +    /// `sum` or `product`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
 +    /// ```
 +    /// This could be written as:
 +    /// ```rust
 +    /// let _ = (0..3).any(|x| x > 2);
 +    /// ```
 +    pub UNNECESSARY_FOLD,
 +    style,
 +    "using `fold` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `filter_map` calls which could be replaced by `filter` or `map`.
 +    /// More specifically it checks if the closure provided is only performing one of the
 +    /// filter or map operations and suggests the appropriate option.
 +    ///
 +    /// ### Why is this bad?
 +    /// Complexity. The intent is also clearer if only a single
 +    /// operation is being performed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
 +    ///
 +    /// // As there is no transformation of the argument this could be written as:
 +    /// let _ = (0..3).filter(|&x| x > 2);
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// let _ = (0..4).filter_map(|x| Some(x + 1));
 +    ///
 +    /// // As there is no conditional check on the argument this could be written as:
 +    /// let _ = (0..4).map(|x| x + 1);
 +    /// ```
 +    pub UNNECESSARY_FILTER_MAP,
 +    complexity,
 +    "using `filter_map` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `into_iter` calls on references which should be replaced by `iter`
 +    /// or `iter_mut`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability. Calling `into_iter` on a reference will not move out its
 +    /// content into the resulting iterator, which is confusing. It is better just call `iter` or
 +    /// `iter_mut` directly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let _ = (&vec![3, 4, 5]).into_iter();
 +    ///
 +    /// // Good
 +    /// let _ = (&vec![3, 4, 5]).iter();
 +    /// ```
 +    pub INTO_ITER_ON_REF,
 +    style,
 +    "using `.into_iter()` on a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `map` followed by a `count`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It looks suspicious. Maybe `map` was confused with `filter`.
++    /// If the `map` call is intentional, this should be rewritten
++    /// using `inspect`. Or, if you intend to drive the iterator to
++    /// completion, you can just use `for_each` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).map(|x| x + 2).count();
 +    /// ```
 +    pub SUSPICIOUS_MAP,
 +    suspicious,
 +    "suspicious usage of map"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `MaybeUninit::uninit().assume_init()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// For most types, this is undefined behavior.
 +    ///
 +    /// ### Known problems
 +    /// For now, we accept empty tuples and tuples / arrays
 +    /// of `MaybeUninit`. There may be other types that allow uninitialized
 +    /// data, but those are not yet rigorously defined.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Beware the UB
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
 +    /// ```
 +    ///
 +    /// Note that the following is OK:
 +    ///
 +    /// ```rust
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: [MaybeUninit<bool>; 5] = unsafe {
 +    ///     MaybeUninit::uninit().assume_init()
 +    /// };
 +    /// ```
 +    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
 +    ///
 +    /// ### 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
 +    /// `_.as_deref()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_ref().map(String::as_str)
 +    /// # ;
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_deref()
 +    /// # ;
 +    /// ```
 +    pub OPTION_AS_REF_DEREF,
 +    complexity,
 +    "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `iter().next()` on a Slice or an Array
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be shortened into `.get()`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a[2..].iter().next();
 +    /// b.iter().next();
 +    /// ```
 +    /// should be written as:
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a.get(2);
 +    /// b.get(0);
 +    /// ```
 +    pub ITER_NEXT_SLICE,
 +    style,
 +    "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns when using `push_str`/`insert_str` with a single-character string literal
 +    /// where `push`/`insert` with a `char` would work fine.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's less clear that we are pushing a single character.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut string = String::new();
 +    /// string.insert_str(0, "R");
 +    /// string.push_str("R");
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let mut string = String::new();
 +    /// string.insert(0, 'R');
 +    /// string.push('R');
 +    /// ```
 +    pub SINGLE_CHAR_ADD_STR,
 +    style,
 +    "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// As the counterpart to `or_fun_call`, this lint looks for unnecessary
 +    /// lazily evaluated closures on `Option` and `Result`.
 +    ///
 +    /// This lint suggests changing the following functions, when eager evaluation results in
 +    /// simpler code:
 +    ///  - `unwrap_or_else` to `unwrap_or`
 +    ///  - `and_then` to `and`
 +    ///  - `or_else` to `or`
 +    ///  - `get_or_insert_with` to `get_or_insert`
 +    ///  - `ok_or_else` to `ok_or`
 +    ///
 +    /// ### Why is this bad?
 +    /// Using eager evaluation is shorter and simpler in some cases.
 +    ///
 +    /// ### Known problems
 +    /// It is possible, but not recommended for `Deref` and `Index` to have
 +    /// side effects. Eagerly evaluating them can change the semantics of the program.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or_else(|| 42);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or(42);
 +    /// ```
 +    pub UNNECESSARY_LAZY_EVALUATIONS,
 +    style,
 +    "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map(_).collect::<Result<(), _>()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `try_for_each` instead is more readable and idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// (0..3).try_for_each(|t| Err(t));
 +    /// ```
 +    pub MAP_COLLECT_RESULT_UNIT,
 +    style,
 +    "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `from_iter()` function calls on types that implement the `FromIterator`
 +    /// trait.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is recommended style to use collect. See
 +    /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::iter::FromIterator;
 +    ///
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v = Vec::from_iter(five_fives);
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v: Vec<i32> = five_fives.collect();
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    pub FROM_ITER_INSTEAD_OF_COLLECT,
 +    pedantic,
 +    "use `.collect()` instead of `::from_iter()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `inspect().for_each()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is the same as performing the computation
 +    /// inside `inspect` at the beginning of the closure in `for_each`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .inspect(|&x| println!("inspect the number: {}", x))
 +    /// .for_each(|&x| {
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .for_each(|&x| {
 +    ///     println!("inspect the number: {}", x);
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    pub INSPECT_FOR_EACH,
 +    complexity,
 +    "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `filter_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.filter_map(|x| x);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    pub FILTER_MAP_IDENTITY,
 +    complexity,
 +    "call to `filter_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for instances of `map(f)` where `f` is the identity function.
 +    ///
 +    /// ### Why is this bad?
 +    /// It can be written more concisely without the call to `map`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
 +    /// ```
 +    pub MAP_IDENTITY,
 +    complexity,
 +    "using iterator.map(|x| x)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.bytes().nth()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.as_bytes().get()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let _ = "Hello".bytes().nth(3);
 +    ///
 +    /// // Good
 +    /// let _ = "Hello".as_bytes().get(3);
 +    /// ```
 +    pub BYTES_NTH,
 +    style,
 +    "replace `.bytes().nth()` with `.as_bytes().get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
 +    ///
 +    /// ### Why is this bad?
 +    /// These methods do the same thing as `_.clone()` but may be confusing as
 +    /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.to_vec();
 +    /// let c = a.to_owned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.clone();
 +    /// let c = a.clone();
 +    /// ```
 +    pub IMPLICIT_CLONE,
 +    pedantic,
 +    "implicitly cloning a value by invoking a function on its dereferenced type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.iter().count()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.len()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.iter().count();
 +    /// let _ = &some_vec[..].iter().count();
 +    ///
 +    /// // Good
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.len();
 +    /// let _ = &some_vec[..].len();
 +    /// ```
 +    pub ITER_COUNT,
 +    complexity,
 +    "replace `.iter().count()` with `.len()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to [`splitn`]
 +    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
 +    /// related functions with either zero or one splits.
 +    ///
 +    /// ### Why is this bad?
 +    /// These calls don't actually split the value and are
 +    /// likely to be intended as a different number.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let s = "";
 +    /// for x in s.splitn(1, ":") {
 +    ///     // use x
 +    /// }
 +    ///
 +    /// // Good
 +    /// let s = "";
 +    /// for x in s.splitn(2, ":") {
 +    ///     // use x
 +    /// }
 +    /// ```
 +    pub SUSPICIOUS_SPLITN,
 +    correctness,
 +    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for manual implementations of `str::repeat`
 +    ///
 +    /// ### Why is this bad?
 +    /// These are both harder to read, as well as less performant.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let x: String = std::iter::repeat('x').take(10).collect();
 +    ///
 +    /// // Good
 +    /// let x: String = "x".repeat(10);
 +    /// ```
 +    pub MANUAL_STR_REPEAT,
 +    perf,
 +    "manual implementation of `str::repeat`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for usages of `str::splitn(2, _)`
 +    ///
 +    /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust,ignore
 +    /// // Bad
 +    ///  let (key, value) = _.splitn(2, '=').next_tuple()?;
 +    ///  let value = _.splitn(2, '=').nth(1)?;
 +    ///
 +    /// // Good
 +    /// let (key, value) = _.split_once('=')?;
 +    /// let value = _.split_once('=')?.1;
 +    /// ```
 +    pub MANUAL_SPLIT_ONCE,
 +    complexity,
 +    "replace `.splitn(2, pat)` with `.split_once(pat)`"
 +}
 +
 +pub struct Methods {
 +    avoid_breaking_exported_api: bool,
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl Methods {
 +    #[must_use]
 +    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            avoid_breaking_exported_api,
 +            msrv,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(Methods => [
 +    UNWRAP_USED,
 +    EXPECT_USED,
 +    SHOULD_IMPLEMENT_TRAIT,
 +    WRONG_SELF_CONVENTION,
 +    OK_EXPECT,
 +    UNWRAP_OR_ELSE_DEFAULT,
 +    MAP_UNWRAP_OR,
 +    RESULT_MAP_OR_INTO_OPTION,
 +    OPTION_MAP_OR_NONE,
 +    BIND_INSTEAD_OF_MAP,
 +    OR_FUN_CALL,
 +    EXPECT_FUN_CALL,
 +    CHARS_NEXT_CMP,
 +    CHARS_LAST_CMP,
 +    CLONE_ON_COPY,
 +    CLONE_ON_REF_PTR,
 +    CLONE_DOUBLE_REF,
 +    CLONED_INSTEAD_OF_COPIED,
 +    FLAT_MAP_OPTION,
 +    INEFFICIENT_TO_STRING,
 +    NEW_RET_NO_SELF,
 +    SINGLE_CHAR_PATTERN,
 +    SINGLE_CHAR_ADD_STR,
 +    SEARCH_IS_SOME,
 +    FILTER_NEXT,
 +    SKIP_WHILE_NEXT,
 +    FILTER_MAP_IDENTITY,
 +    MAP_IDENTITY,
 +    MANUAL_FILTER_MAP,
 +    MANUAL_FIND_MAP,
 +    OPTION_FILTER_MAP,
 +    FILTER_MAP_NEXT,
 +    FLAT_MAP_IDENTITY,
 +    MAP_FLATTEN,
 +    ITERATOR_STEP_BY_ZERO,
 +    ITER_NEXT_SLICE,
 +    ITER_COUNT,
 +    ITER_NTH,
 +    ITER_NTH_ZERO,
 +    BYTES_NTH,
 +    ITER_SKIP_NEXT,
 +    GET_UNWRAP,
 +    STRING_EXTEND_CHARS,
 +    ITER_CLONED_COLLECT,
 +    USELESS_ASREF,
 +    UNNECESSARY_FOLD,
 +    UNNECESSARY_FILTER_MAP,
 +    INTO_ITER_ON_REF,
 +    SUSPICIOUS_MAP,
 +    UNINIT_ASSUMED_INIT,
 +    MANUAL_SATURATING_ARITHMETIC,
 +    ZST_OFFSET,
 +    FILETYPE_IS_FILE,
 +    OPTION_AS_REF_DEREF,
 +    UNNECESSARY_LAZY_EVALUATIONS,
 +    MAP_COLLECT_RESULT_UNIT,
 +    FROM_ITER_INSTEAD_OF_COLLECT,
 +    INSPECT_FOR_EACH,
 +    IMPLICIT_CLONE,
 +    SUSPICIOUS_SPLITN,
 +    MANUAL_STR_REPEAT,
 +    EXTEND_WITH_DRAIN,
 +    MANUAL_SPLIT_ONCE
 +]);
 +
 +/// Extracts a method call name, args, and `Span` of the method name.
 +fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(SymbolStr, &'tcx [hir::Expr<'tcx>], Span)> {
 +    if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
 +        if !args.iter().any(|e| e.span.from_expansion()) {
 +            return Some((path.ident.name.as_str(), args, span));
 +        }
 +    }
 +    None
 +}
 +
 +/// Same as `method_call` but the `SymbolStr` is dereferenced into a temporary `&str`
 +macro_rules! method_call {
 +    ($expr:expr) => {
 +        method_call($expr)
 +            .as_ref()
 +            .map(|&(ref name, args, span)| (&**name, args, span))
 +    };
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Methods {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if in_macro(expr.span) {
 +            return;
 +        }
 +
 +        check_methods(cx, expr, self.msrv.as_ref());
 +
 +        match expr.kind {
 +            hir::ExprKind::Call(func, args) => {
 +                from_iter_instead_of_collect::check(cx, expr, args, func);
 +            },
 +            hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
 +                or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
 +                expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
 +                clone_on_copy::check(cx, expr, method_call.ident.name, args);
 +                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
 +                inefficient_to_string::check(cx, expr, method_call.ident.name, args);
 +                single_char_add_str::check(cx, expr, args);
 +                into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
 +                single_char_pattern::check(cx, expr, method_call.ident.name, args);
 +            },
 +            hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
 +                let mut info = BinaryExprInfo {
 +                    expr,
 +                    chain: lhs,
 +                    other: rhs,
 +                    eq: op.node == hir::BinOpKind::Eq,
 +                };
 +                lint_binary_expr_with_method_call(cx, &mut info);
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
 +        if in_external_macro(cx.sess(), impl_item.span) {
 +            return;
 +        }
 +        let name = impl_item.ident.name.as_str();
 +        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
 +        let item = cx.tcx.hir().expect_item(parent);
 +        let self_ty = cx.tcx.type_of(item.def_id);
 +
 +        let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
 +        if_chain! {
 +            if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
 +            if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
 +
 +            let method_sig = cx.tcx.fn_sig(impl_item.def_id);
 +            let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
 +
 +            let first_arg_ty = &method_sig.inputs().iter().next();
 +
 +            // check conventions w.r.t. conversion method names and predicates
 +            if let Some(first_arg_ty) = first_arg_ty;
 +
 +            then {
 +                // if this impl block implements a trait, lint in trait definition instead
 +                if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
 +                    // check missing trait implementations
 +                    for method_config in &TRAIT_METHODS {
 +                        if name == method_config.method_name &&
 +                            sig.decl.inputs.len() == method_config.param_count &&
 +                            method_config.output_type.matches(&sig.decl.output) &&
 +                            method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
 +                            fn_header_equals(method_config.fn_header, sig.header) &&
 +                            method_config.lifetime_param_cond(impl_item)
 +                        {
 +                            span_lint_and_help(
 +                                cx,
 +                                SHOULD_IMPLEMENT_TRAIT,
 +                                impl_item.span,
 +                                &format!(
 +                                    "method `{}` can be confused for the standard trait method `{}::{}`",
 +                                    method_config.method_name,
 +                                    method_config.trait_name,
 +                                    method_config.method_name
 +                                ),
 +                                None,
 +                                &format!(
 +                                    "consider implementing the trait `{}` or choosing a less ambiguous method name",
 +                                    method_config.trait_name
 +                                )
 +                            );
 +                        }
 +                    }
 +                }
 +
 +                if sig.decl.implicit_self.has_implicit_self()
 +                    && !(self.avoid_breaking_exported_api
 +                        && cx.access_levels.is_exported(impl_item.def_id))
 +                {
 +                    wrong_self_convention::check(
 +                        cx,
 +                        &name,
 +                        self_ty,
 +                        first_arg_ty,
 +                        first_arg.pat.span,
 +                        implements_trait,
 +                        false
 +                    );
 +                }
 +            }
 +        }
 +
 +        // if this impl block implements a trait, lint in trait definition instead
 +        if implements_trait {
 +            return;
 +        }
 +
 +        if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
 +            let ret_ty = return_ty(cx, impl_item.hir_id());
 +
 +            // walk the return type and check for Self (this does not check associated types)
 +            if let Some(self_adt) = self_ty.ty_adt_def() {
 +                if contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
 +                    return;
 +                }
 +            } else if contains_ty(cx.tcx, ret_ty, self_ty) {
 +                return;
 +            }
 +
 +            // if return type is impl trait, check the associated types
 +            if let ty::Opaque(def_id, _) = *ret_ty.kind() {
 +                // one of the associated types must be Self
 +                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
 +                    if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
 +                        // walk the associated type and check for Self
 +                        if let Some(self_adt) = self_ty.ty_adt_def() {
 +                            if contains_adt_constructor(cx.tcx, projection_predicate.ty, self_adt) {
 +                                return;
 +                            }
 +                        } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +
 +            if name == "new" && !TyS::same_type(ret_ty, self_ty) {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    impl_item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let TraitItemKind::Fn(ref sig, _) = item.kind;
 +            if sig.decl.implicit_self.has_implicit_self();
 +            if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
 +
 +            then {
 +                let first_arg_span = first_arg_ty.span;
 +                let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
 +                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
 +                wrong_self_convention::check(
 +                    cx,
 +                    &item.ident.name.as_str(),
 +                    self_ty,
 +                    first_arg_ty,
 +                    first_arg_span,
 +                    false,
 +                    true
 +                );
 +            }
 +        }
 +
 +        if_chain! {
 +            if item.ident.name == sym::new;
 +            if let TraitItemKind::Fn(_, _) = item.kind;
 +            let ret_ty = return_ty(cx, item.hir_id());
 +            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
 +            if !contains_ty(cx.tcx, ret_ty, self_ty);
 +
 +            then {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
 +    if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
 +        match (name, args) {
 +            ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
 +                zst_offset::check(cx, expr, recv);
 +            },
 +            ("and_then", [arg]) => {
 +                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
 +                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
 +                if !biom_option_linted && !biom_result_linted {
 +                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
 +                }
 +            },
 +            ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
 +            ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
 +            ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
 +            ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
 +            ("collect", []) => match method_call!(recv) {
 +                Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
 +                Some(("map", [m_recv, m_arg], _)) => {
 +                    map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
 +                },
 +                Some(("take", [take_self_arg, take_arg], _)) => {
 +                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
 +                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
 +                    }
 +                },
 +                _ => {},
 +            },
 +            ("count", []) => match method_call!(recv) {
 +                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
 +                    iter_count::check(cx, expr, recv2, name);
 +                },
 +                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
 +                _ => {},
 +            },
 +            ("expect", [_]) => match method_call!(recv) {
 +                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
 +                _ => expect_used::check(cx, expr, recv),
 +            },
 +            ("extend", [arg]) => {
 +                string_extend_chars::check(cx, expr, recv, arg);
 +                extend_with_drain::check(cx, expr, recv, arg);
 +            },
 +            ("filter_map", [arg]) => {
 +                unnecessary_filter_map::check(cx, expr, arg);
 +                filter_map_identity::check(cx, expr, arg, span);
 +            },
 +            ("flat_map", [arg]) => {
 +                flat_map_identity::check(cx, expr, arg, span);
 +                flat_map_option::check(cx, expr, arg, span);
 +            },
 +            ("flatten", []) => {
 +                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
 +                    map_flatten::check(cx, expr, recv, map_arg);
 +                }
 +            },
 +            ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
 +            ("for_each", [_]) => {
 +                if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
 +                    inspect_for_each::check(cx, expr, span2);
 +                }
 +            },
 +            ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
 +            ("is_file", []) => filetype_is_file::check(cx, expr, recv),
 +            ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
 +            ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
 +            ("map", [m_arg]) => {
 +                if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
 +                    match (name, args) {
 +                        ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
 +                        ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
 +                        ("filter", [f_arg]) => {
 +                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
 +                        },
 +                        ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
 +                        _ => {},
 +                    }
 +                }
 +                map_identity::check(cx, expr, recv, m_arg, span);
 +            },
 +            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
 +            ("next", []) => {
 +                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
 +                    match (name, args) {
 +                        ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
 +                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
 +                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
 +                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
 +                        ("skip_while", [_]) => skip_while_next::check(cx, expr),
 +                        _ => {},
 +                    }
 +                }
 +            },
 +            ("nth", [n_arg]) => match method_call!(recv) {
 +                Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
 +                Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
 +                Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
 +                _ => iter_nth_zero::check(cx, expr, recv, n_arg),
 +            },
 +            ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
 +            ("or_else", [arg]) => {
 +                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
 +                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
 +                }
 +            },
 +            ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
 +                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
 +                    suspicious_splitn::check(cx, name, expr, recv, count);
 +                    if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
 +                        manual_split_once::check(cx, name, expr, recv, pat_arg);
 +                    }
 +                }
 +            },
 +            ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
 +                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
 +                    suspicious_splitn::check(cx, name, expr, recv, count);
 +                }
 +            },
 +            ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
 +            ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
 +                implicit_clone::check(cx, name, expr, recv, span);
 +            },
 +            ("unwrap", []) => match method_call!(recv) {
 +                Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
 +                Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
 +                _ => unwrap_used::check(cx, expr, recv),
 +            },
 +            ("unwrap_or", [u_arg]) => match method_call!(recv) {
 +                Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
 +                    manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
 +                },
 +                Some(("map", [m_recv, m_arg], span)) => {
 +                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
 +                },
 +                _ => {},
 +            },
 +            ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
 +                Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
 +                _ => {
 +                    unwrap_or_else_default::check(cx, expr, recv, u_arg);
 +                    unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
 +                },
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
 +    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
 +        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
 +    }
 +}
 +
 +/// Used for `lint_binary_expr_with_method_call`.
 +#[derive(Copy, Clone)]
 +struct BinaryExprInfo<'a> {
 +    expr: &'a hir::Expr<'a>,
 +    chain: &'a hir::Expr<'a>,
 +    other: &'a hir::Expr<'a>,
 +    eq: bool,
 +}
 +
 +/// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 +fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
 +    macro_rules! lint_with_both_lhs_and_rhs {
 +        ($func:expr, $cx:expr, $info:ident) => {
 +            if !$func($cx, $info) {
 +                ::std::mem::swap(&mut $info.chain, &mut $info.other);
 +                if $func($cx, $info) {
 +                    return;
 +                }
 +            }
 +        };
 +    }
 +
 +    lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
 +    lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
 +}
 +
 +const FN_HEADER: hir::FnHeader = hir::FnHeader {
 +    unsafety: hir::Unsafety::Normal,
 +    constness: hir::Constness::NotConst,
 +    asyncness: hir::IsAsync::NotAsync,
 +    abi: rustc_target::spec::abi::Abi::Rust,
 +};
 +
 +struct ShouldImplTraitCase {
 +    trait_name: &'static str,
 +    method_name: &'static str,
 +    param_count: usize,
 +    fn_header: hir::FnHeader,
 +    // implicit self kind expected (none, self, &self, ...)
 +    self_kind: SelfKind,
 +    // checks against the output type
 +    output_type: OutType,
 +    // certain methods with explicit lifetimes can't implement the equivalent trait method
 +    lint_explicit_lifetime: bool,
 +}
 +impl ShouldImplTraitCase {
 +    const fn new(
 +        trait_name: &'static str,
 +        method_name: &'static str,
 +        param_count: usize,
 +        fn_header: hir::FnHeader,
 +        self_kind: SelfKind,
 +        output_type: OutType,
 +        lint_explicit_lifetime: bool,
 +    ) -> ShouldImplTraitCase {
 +        ShouldImplTraitCase {
 +            trait_name,
 +            method_name,
 +            param_count,
 +            fn_header,
 +            self_kind,
 +            output_type,
 +            lint_explicit_lifetime,
 +        }
 +    }
 +
 +    fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
 +        self.lint_explicit_lifetime
 +            || !impl_item.generics.params.iter().any(|p| {
 +                matches!(
 +                    p.kind,
 +                    hir::GenericParamKind::Lifetime {
 +                        kind: hir::LifetimeParamKind::Explicit
 +                    }
 +                )
 +            })
 +    }
 +}
 +
 +#[rustfmt::skip]
 +const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
 +    ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
 +    // FIXME: default doesn't work
 +    ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
 +    ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
 +    ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
 +    ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
 +    ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
 +    ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +    ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 +];
 +
 +#[derive(Clone, Copy, PartialEq, Debug)]
 +enum SelfKind {
 +    Value,
 +    Ref,
 +    RefMut,
 +    No,
 +}
 +
 +impl SelfKind {
 +    fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +        fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
 +            if ty == parent_ty {
 +                true
 +            } else if ty.is_box() {
 +                ty.boxed_ty() == parent_ty
 +            } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
 +                if let ty::Adt(_, substs) = ty.kind() {
 +                    substs.types().next().map_or(false, |t| t == parent_ty)
 +                } else {
 +                    false
 +                }
 +            } else {
 +                false
 +            }
 +        }
 +
 +        fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +            if let ty::Ref(_, t, m) = *ty.kind() {
 +                return m == mutability && t == parent_ty;
 +            }
 +
 +            let trait_path = match mutability {
 +                hir::Mutability::Not => &paths::ASREF_TRAIT,
 +                hir::Mutability::Mut => &paths::ASMUT_TRAIT,
 +            };
 +
 +            let trait_def_id = match get_trait_def_id(cx, trait_path) {
 +                Some(did) => did,
 +                None => return false,
 +            };
 +            implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
 +        }
 +
 +        match self {
 +            Self::Value => matches_value(cx, parent_ty, ty),
 +            Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
 +            Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
 +            Self::No => ty != parent_ty,
 +        }
 +    }
 +
 +    #[must_use]
 +    fn description(self) -> &'static str {
 +        match self {
 +            Self::Value => "`self` by value",
 +            Self::Ref => "`self` by reference",
 +            Self::RefMut => "`self` by mutable reference",
 +            Self::No => "no `self`",
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OutType {
 +    Unit,
 +    Bool,
 +    Any,
 +    Ref,
 +}
 +
 +impl OutType {
 +    fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
 +        let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
 +        match (self, ty) {
 +            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
 +            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
 +            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
 +            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
 +            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn is_bool(ty: &hir::Ty<'_>) -> bool {
 +    if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +        matches!(path.res, Res::PrimTy(PrimTy::Bool))
 +    } else {
 +        false
 +    }
 +}
 +
 +fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
 +    expected.constness == actual.constness
 +        && expected.unsafety == actual.unsafety
 +        && expected.asyncness == actual.asyncness
 +}
index cabbb8400767d104a08da17d0141668017c4eb13,0000000000000000000000000000000000000000..b5bbbb09092af4f12d27c6fc60cc363444796019
mode 100644,000000..100644
--- /dev/null
@@@ -1,193 -1,0 +1,193 @@@
-             hir::ExprKind::Block(block, _) => {
-                 if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules {
-                     if let Some(block_expr) = block.expr {
-                         if let hir::ExprKind::MethodCall(..) = block_expr.kind {
-                             check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
-                         }
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::eager_or_lazy::is_lazyness_candidate;
 +use clippy_utils::is_trait_item;
 +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
 +use clippy_utils::ty::implements_trait;
 +use clippy_utils::ty::{is_type_diagnostic_item, match_type};
 +use clippy_utils::{contains_return, last_path_segment, paths};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::{BlockCheckMode, UnsafeSource};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty;
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{kw, sym};
 +use std::borrow::Cow;
 +
 +use super::OR_FUN_CALL;
 +
 +/// Checks for the `OR_FUN_CALL` lint.
 +#[allow(clippy::too_many_lines)]
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +    method_span: Span,
 +    name: &str,
 +    args: &'tcx [hir::Expr<'_>],
 +) {
 +    /// 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 {
 +        let is_default_default = || is_trait_item(cx, fun, sym::Default);
 +
 +        let implements_default = |arg, default_trait_id| {
 +            let arg_ty = cx.typeck_results().expr_ty(arg);
 +            implements_trait(cx, arg_ty, default_trait_id, &[])
 +        };
 +
 +        if_chain! {
 +            if !or_has_args;
 +            if name == "unwrap_or";
 +            if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
 +            let path = last_path_segment(qpath).ident.name;
 +            // needs to target Default::default in particular or be *::new and have a Default impl
 +            // available
 +            if (matches!(path, kw::Default) && is_default_default())
 +                || (matches!(path, sym::new) && implements_default(arg, 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,
 +        self_expr: &hir::Expr<'_>,
 +        arg: &'tcx hir::Expr<'_>,
 +        span: Span,
 +        // None if lambda is required
 +        fun_span: Option<Span>,
 +    ) {
 +        // (path, fn_has_argument, methods, suffix)
 +        static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
 +            (&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 let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind {
 +            if path.ident.name == sym::len {
 +                let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +
 +                match ty.kind() {
 +                    ty::Slice(_) | ty::Array(_, _) | ty::Str => return,
 +                    _ => (),
 +                }
 +
 +                if is_type_diagnostic_item(cx, ty, sym::Vec) {
 +                    return;
 +                }
 +            }
 +        }
 +
 +        if_chain! {
 +            if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
 +
 +            if is_lazyness_candidate(cx, arg);
 +            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 macro_expanded_snipped;
 +                let sugg: Cow<'_, str> = {
 +                    let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
 +                        (false, Some(fun_span)) => (fun_span, false),
 +                        _ => (arg.span, true),
 +                    };
 +                    let snippet = {
 +                        let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
 +                        if not_macro_argument_snippet == "vec![]" {
 +                            macro_expanded_snipped = snippet(cx, snippet_span, "..");
 +                            match macro_expanded_snipped.strip_prefix("$crate::vec::") {
 +                                Some(stripped) => Cow::from(stripped),
 +                                None => macro_expanded_snipped
 +                            }
 +                        }
 +                        else {
 +                            not_macro_argument_snippet
 +                        }
 +                    };
 +
 +                    if use_lambda {
 +                        let l_arg = if fn_has_arguments { "_" } else { "" };
 +                        format!("|{}| {}", l_arg, snippet).into()
 +                    } else {
 +                        snippet
 +                    }
 +                };
 +                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(fun, 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) {
 +                    let fun_span = if or_has_args { None } else { Some(fun.span) };
 +                    check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
 +                }
 +            },
 +            hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
 +                check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
 +            },
-             },
++            hir::ExprKind::Block(block, _)
++                if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) =>
++            {
++                if let Some(block_expr) = block.expr {
++                    if let hir::ExprKind::MethodCall(..) = block_expr.kind {
++                        check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
 +                    }
 +                }
++            }
 +            _ => (),
 +        }
 +    }
 +}
index 0fd0668c734022b4e4834781c1bdba1128a3b78e,0000000000000000000000000000000000000000..18ded291915e104c48374d83c6d8802123129c61
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,35 @@@
-                 "make sure you did not confuse `map` with `filter` or `for_each`",
 +use clippy_utils::diagnostics::span_lint_and_help;
 +use clippy_utils::usage::mutated_variables;
 +use clippy_utils::{expr_or_init, is_trait_method};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +use super::SUSPICIOUS_MAP;
 +
 +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
 +    if_chain! {
 +        if is_trait_method(cx, count_recv, sym::Iterator);
 +        let closure = expr_or_init(cx, map_arg);
 +        if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id);
 +        let closure_body = cx.tcx.hir().body(body_id);
 +        if !cx.typeck_results().expr_ty(&closure_body.value).is_unit();
 +        then {
 +            if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) {
 +                // A variable is used mutably inside of the closure. Suppress the lint.
 +                if !map_mutated_vars.is_empty() {
 +                    return;
 +                }
 +            }
 +            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`, `for_each` or `inspect`",
 +            );
 +        }
 +    }
 +}
index a9d3764d92d443d7ea52bb4e2702804cc940579f,0000000000000000000000000000000000000000..59bdfb923ed49f2229c00b478677f78fb05b2717
mode 100644,000000..100644
--- /dev/null
@@@ -1,132 -1,0 +1,131 @@@
-                     if cx.tcx.is_diagnostic_item(sym::Option, adt.did)
-                         && TyS::same_type(in_ty, subst.type_at(0)) =>
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::usage::mutated_variables;
 +use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id};
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::LangItem::{OptionNone, OptionSome};
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::ty::{self, TyS};
 +use rustc_span::sym;
 +
 +use super::UNNECESSARY_FILTER_MAP;
 +
 +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
 +    if !is_trait_method(cx, expr, sym::Iterator) {
 +        return;
 +    }
 +
 +    if let hir::ExprKind::Closure(_, _, body_id, ..) = arg.kind {
 +        let body = cx.tcx.hir().body(body_id);
 +        let arg_id = body.params[0].pat.hir_id;
 +        let mutates_arg =
 +            mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
 +
 +        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
 +
 +        let mut return_visitor = ReturnVisitor::new(cx, arg_id);
 +        return_visitor.visit_expr(&body.value);
 +        found_mapping |= return_visitor.found_mapping;
 +        found_filtering |= return_visitor.found_filtering;
 +
 +        let sugg = if !found_filtering {
 +            "map"
 +        } else if !found_mapping && !mutates_arg {
 +            let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
 +            match cx.typeck_results().expr_ty(&body.value).kind() {
 +                ty::Adt(adt, subst)
++                    if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && TyS::same_type(in_ty, subst.type_at(0)) =>
 +                {
 +                    "filter"
 +                },
 +                _ => return,
 +            }
 +        } else {
 +            return;
 +        };
 +        span_lint(
 +            cx,
 +            UNNECESSARY_FILTER_MAP,
 +            expr.span,
 +            &format!("this `.filter_map` can be written more simply using `.{}`", sugg),
 +        );
 +    }
 +}
 +
 +// returns (found_mapping, found_filtering)
 +fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) {
 +    match &expr.kind {
 +        hir::ExprKind::Call(func, args) => {
 +            if let hir::ExprKind::Path(ref path) = func.kind {
 +                if is_lang_ctor(cx, path, OptionSome) {
 +                    if path_to_local_id(&args[0], arg_id) {
 +                        return (false, false);
 +                    }
 +                    return (true, false);
 +                }
 +            }
 +            (true, true)
 +        },
 +        hir::ExprKind::Block(block, _) => block
 +            .expr
 +            .as_ref()
 +            .map_or((false, false), |expr| check_expression(cx, arg_id, expr)),
 +        hir::ExprKind::Match(_, arms, _) => {
 +            let mut found_mapping = false;
 +            let mut found_filtering = false;
 +            for arm in *arms {
 +                let (m, f) = check_expression(cx, arg_id, arm.body);
 +                found_mapping |= m;
 +                found_filtering |= f;
 +            }
 +            (found_mapping, found_filtering)
 +        },
 +        // There must be an else_arm or there will be a type error
 +        hir::ExprKind::If(_, if_arm, Some(else_arm)) => {
 +            let if_check = check_expression(cx, arg_id, if_arm);
 +            let else_check = check_expression(cx, arg_id, else_arm);
 +            (if_check.0 | else_check.0, if_check.1 | else_check.1)
 +        },
 +        hir::ExprKind::Path(path) if is_lang_ctor(cx, path, OptionNone) => (false, true),
 +        _ => (true, true),
 +    }
 +}
 +
 +struct ReturnVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    arg_id: hir::HirId,
 +    // Found a non-None return that isn't Some(input)
 +    found_mapping: bool,
 +    // Found a return that isn't Some
 +    found_filtering: bool,
 +}
 +
 +impl<'a, 'tcx> ReturnVisitor<'a, 'tcx> {
 +    fn new(cx: &'a LateContext<'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx> {
 +        ReturnVisitor {
 +            cx,
 +            arg_id,
 +            found_mapping: false,
 +            found_filtering: false,
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +        if let hir::ExprKind::Ret(Some(expr)) = &expr.kind {
 +            let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
 +            self.found_mapping |= found_mapping;
 +            self.found_filtering |= found_filtering;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index 2d14943b56c95fbffbb2d20ddd8c2a4bfbf9897b,0000000000000000000000000000000000000000..f45e68233a1777f5c0052e7b0a0758b024a1c306
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,149 @@@
-                 if let BinOpKind::Rem = op.node {
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::sext;
 +use if_chain::if_chain;
 +use rustc_hir::{BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use std::fmt::Display;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for modulo arithmetic.
 +    ///
 +    /// ### Why is this bad?
 +    /// The results of modulo (%) operation might differ
 +    /// depending on the language, when negative numbers are involved.
 +    /// If you interop with different languages it might be beneficial
 +    /// to double check all places that use modulo arithmetic.
 +    ///
 +    /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = -17 % 3;
 +    /// ```
 +    pub MODULO_ARITHMETIC,
 +    restriction,
 +    "any modulo arithmetic statement"
 +}
 +
 +declare_lint_pass!(ModuloArithmetic => [MODULO_ARITHMETIC]);
 +
 +struct OperandInfo {
 +    string_representation: Option<String>,
 +    is_negative: bool,
 +    is_integral: bool,
 +}
 +
 +fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
 +    match constant(cx, cx.typeck_results(), operand) {
 +        Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() {
 +            ty::Int(ity) => {
 +                let value = sext(cx.tcx, v, ity);
 +                return Some(OperandInfo {
 +                    string_representation: Some(value.to_string()),
 +                    is_negative: value < 0,
 +                    is_integral: true,
 +                });
 +            },
 +            ty::Uint(_) => {
 +                return Some(OperandInfo {
 +                    string_representation: None,
 +                    is_negative: false,
 +                    is_integral: true,
 +                });
 +            },
 +            _ => {},
 +        },
 +        Some((Constant::F32(f), _)) => {
 +            return Some(floating_point_operand_info(&f));
 +        },
 +        Some((Constant::F64(f), _)) => {
 +            return Some(floating_point_operand_info(&f));
 +        },
 +        _ => {},
 +    }
 +    None
 +}
 +
 +fn floating_point_operand_info<T: Display + PartialOrd + From<f32>>(f: &T) -> OperandInfo {
 +    OperandInfo {
 +        string_representation: Some(format!("{:.3}", *f)),
 +        is_negative: *f < 0.0.into(),
 +        is_integral: false,
 +    }
 +}
 +
 +fn might_have_negative_value(t: &ty::TyS<'_>) -> bool {
 +    t.is_signed() || t.is_floating_point()
 +}
 +
 +fn check_const_operands<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    lhs_operand: &OperandInfo,
 +    rhs_operand: &OperandInfo,
 +) {
 +    if lhs_operand.is_negative ^ rhs_operand.is_negative {
 +        span_lint_and_then(
 +            cx,
 +            MODULO_ARITHMETIC,
 +            expr.span,
 +            &format!(
 +                "you are using modulo operator on constants with different signs: `{} % {}`",
 +                lhs_operand.string_representation.as_ref().unwrap(),
 +                rhs_operand.string_representation.as_ref().unwrap()
 +            ),
 +            |diag| {
 +                diag.note("double check for expected result especially when interoperating with different languages");
 +                if lhs_operand.is_integral {
 +                    diag.note("or consider using `rem_euclid` or similar function");
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +fn check_non_const_operands<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) {
 +    let operand_type = cx.typeck_results().expr_ty(operand);
 +    if might_have_negative_value(operand_type) {
 +        span_lint_and_then(
 +            cx,
 +            MODULO_ARITHMETIC,
 +            expr.span,
 +            "you are using modulo operator on types that might have different signs",
 +            |diag| {
 +                diag.note("double check for expected result especially when interoperating with different languages");
 +                if operand_type.is_integral() {
 +                    diag.note("or consider using `rem_euclid` or similar function");
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for ModuloArithmetic {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        match &expr.kind {
 +            ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => {
++                if op.node == BinOpKind::Rem {
 +                    let lhs_operand = analyze_operand(lhs, cx, expr);
 +                    let rhs_operand = analyze_operand(rhs, cx, expr);
 +                    if_chain! {
 +                        if let Some(lhs_operand) = lhs_operand;
 +                        if let Some(rhs_operand) = rhs_operand;
 +                        then {
 +                            check_const_operands(cx, expr, &lhs_operand, &rhs_operand);
 +                        }
 +                        else {
 +                            check_non_const_operands(cx, expr, lhs);
 +                        }
 +                    }
 +                };
 +            },
 +            _ => {},
 +        }
 +    }
 +}
index c9dd94400efb96163f0d01028cc92cb91eef4ecc,0000000000000000000000000000000000000000..91944653500bbde663f4e14c9226279eca4fcacc
mode 100644,000000..100644
--- /dev/null
@@@ -1,369 -1,0 +1,369 @@@
-             if let BinOpKind::Eq = op.node {
 +//! Checks for needless boolean results of if-else expressions
 +//!
 +//! This lint is **warn** by default
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 +use clippy_utils::higher;
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::{is_else_clause, is_expn_of};
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions of the form `if c { true } else {
 +    /// false }` (or vice versa) and suggests using the condition directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code.
 +    ///
 +    /// ### Known problems
 +    /// Maybe false positives: Sometimes, the two branches are
 +    /// painstakingly documented (which we, of course, do not detect), so they *may*
 +    /// have some value. Even then, the documentation can be rewritten to match the
 +    /// shorter code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// if x {
 +    ///     false
 +    /// } else {
 +    ///     true
 +    /// }
 +    /// ```
 +    /// Could be written as
 +    /// ```rust,ignore
 +    /// !x
 +    /// ```
 +    pub NEEDLESS_BOOL,
 +    complexity,
 +    "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions of the form `x == true`,
 +    /// `x != true` and order comparisons such as `x < true` (or vice versa) and
 +    /// suggest using the variable directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// Unnecessary code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// if x == true {}
 +    /// if y == false {}
 +    /// ```
 +    /// use `x` directly:
 +    /// ```rust,ignore
 +    /// if x {}
 +    /// if !y {}
 +    /// ```
 +    pub BOOL_COMPARISON,
 +    complexity,
 +    "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 +}
 +
 +declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
 +
 +impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        use self::Expression::{Bool, RetBool};
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let Some(higher::If {
 +            cond,
 +            then,
 +            r#else: Some(r#else),
 +        }) = higher::If::hir(e)
 +        {
 +            let reduce = |ret, not| {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let snip = Sugg::hir_with_applicability(cx, cond, "<predicate>", &mut applicability);
 +                let mut snip = if not { !snip } else { snip };
 +
 +                if ret {
 +                    snip = snip.make_return();
 +                }
 +
 +                if is_else_clause(cx.tcx, e) {
 +                    snip = snip.blockify();
 +                }
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    NEEDLESS_BOOL,
 +                    e.span,
 +                    "this if-then-else expression returns a bool literal",
 +                    "you can reduce it to",
 +                    snip.to_string(),
 +                    applicability,
 +                );
 +            };
 +            if let ExprKind::Block(then, _) = then.kind {
 +                match (fetch_bool_block(then), fetch_bool_expr(r#else)) {
 +                    (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
 +                        span_lint(
 +                            cx,
 +                            NEEDLESS_BOOL,
 +                            e.span,
 +                            "this if-then-else expression will always return true",
 +                        );
 +                    },
 +                    (RetBool(false), RetBool(false)) | (Bool(false), Bool(false)) => {
 +                        span_lint(
 +                            cx,
 +                            NEEDLESS_BOOL,
 +                            e.span,
 +                            "this if-then-else expression will always return false",
 +                        );
 +                    },
 +                    (RetBool(true), RetBool(false)) => reduce(true, false),
 +                    (Bool(true), Bool(false)) => reduce(false, false),
 +                    (RetBool(false), RetBool(true)) => reduce(true, true),
 +                    (Bool(false), Bool(true)) => reduce(false, true),
 +                    _ => (),
 +                }
 +            } else {
 +                panic!("IfExpr `then` node is not an `ExprKind::Block`");
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]);
 +
 +impl<'tcx> LateLintPass<'tcx> for BoolComparison {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Binary(Spanned { node, .. }, ..) = e.kind {
 +            let ignore_case = None::<(fn(_) -> _, &str)>;
 +            let ignore_no_literal = None::<(fn(_, _) -> _, &str)>;
 +            match node {
 +                BinOpKind::Eq => {
 +                    let true_case = Some((|h| h, "equality checks against true are unnecessary"));
 +                    let false_case = Some((
 +                        |h: Sugg<'_>| !h,
 +                        "equality checks against false can be replaced by a negation",
 +                    ));
 +                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
 +                },
 +                BinOpKind::Ne => {
 +                    let true_case = Some((
 +                        |h: Sugg<'_>| !h,
 +                        "inequality checks against true can be replaced by a negation",
 +                    ));
 +                    let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
 +                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
 +                },
 +                BinOpKind::Lt => check_comparison(
 +                    cx,
 +                    e,
 +                    ignore_case,
 +                    Some((|h| h, "greater than checks against false are unnecessary")),
 +                    Some((
 +                        |h: Sugg<'_>| !h,
 +                        "less than comparison against true can be replaced by a negation",
 +                    )),
 +                    ignore_case,
 +                    Some((
 +                        |l: Sugg<'_>, r: Sugg<'_>| (!l).bit_and(&r),
 +                        "order comparisons between booleans can be simplified",
 +                    )),
 +                ),
 +                BinOpKind::Gt => check_comparison(
 +                    cx,
 +                    e,
 +                    Some((
 +                        |h: Sugg<'_>| !h,
 +                        "less than comparison against true can be replaced by a negation",
 +                    )),
 +                    ignore_case,
 +                    ignore_case,
 +                    Some((|h| h, "greater than checks against false are unnecessary")),
 +                    Some((
 +                        |l: Sugg<'_>, r: Sugg<'_>| l.bit_and(&(!r)),
 +                        "order comparisons between booleans can be simplified",
 +                    )),
 +                ),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +struct ExpressionInfoWithSpan {
 +    one_side_is_unary_not: bool,
 +    left_span: Span,
 +    right_span: Span,
 +}
 +
 +fn is_unary_not(e: &Expr<'_>) -> (bool, Span) {
 +    if let ExprKind::Unary(UnOp::Not, operand) = e.kind {
 +        return (true, operand.span);
 +    }
 +    (false, e.span)
 +}
 +
 +fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan {
 +    let left = is_unary_not(left_side);
 +    let right = is_unary_not(right_side);
 +
 +    ExpressionInfoWithSpan {
 +        one_side_is_unary_not: left.0 != right.0,
 +        left_span: left.1,
 +        right_span: right.1,
 +    }
 +}
 +
 +fn check_comparison<'a, 'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
 +    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
 +) {
 +    use self::Expression::{Bool, Other};
 +
 +    if let ExprKind::Binary(op, left_side, right_side) = e.kind {
 +        let (l_ty, r_ty) = (
 +            cx.typeck_results().expr_ty(left_side),
 +            cx.typeck_results().expr_ty(right_side),
 +        );
 +        if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() {
 +            return;
 +        }
 +        if l_ty.is_bool() && r_ty.is_bool() {
 +            let mut applicability = Applicability::MachineApplicable;
 +
++            if op.node == BinOpKind::Eq {
 +                let expression_info = one_side_is_unary_not(left_side, right_side);
 +                if expression_info.one_side_is_unary_not {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        BOOL_COMPARISON,
 +                        e.span,
 +                        "this comparison might be written more concisely",
 +                        "try simplifying it as shown",
 +                        format!(
 +                            "{} != {}",
 +                            snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
 +                            snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
 +                        ),
 +                        applicability,
 +                    );
 +                }
 +            }
 +
 +            match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
 +                (Bool(true), Other) => left_true.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
 +                }),
 +                (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
 +                }),
 +                (Bool(false), Other) => left_false.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
 +                }),
 +                (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
 +                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
 +                }),
 +                (Other, Other) => no_literal.map_or((), |(h, m)| {
 +                    let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
 +                    let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
 +                    span_lint_and_sugg(
 +                        cx,
 +                        BOOL_COMPARISON,
 +                        e.span,
 +                        m,
 +                        "try simplifying it as shown",
 +                        h(left_side, right_side).to_string(),
 +                        applicability,
 +                    );
 +                }),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn suggest_bool_comparison<'a, 'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    expr: &Expr<'_>,
 +    mut applicability: Applicability,
 +    message: &str,
 +    conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
 +) {
 +    let hint = if expr.span.from_expansion() {
 +        if applicability != Applicability::Unspecified {
 +            applicability = Applicability::MaybeIncorrect;
 +        }
 +        Sugg::hir_with_macro_callsite(cx, expr, "..")
 +    } else {
 +        Sugg::hir_with_applicability(cx, expr, "..", &mut applicability)
 +    };
 +    span_lint_and_sugg(
 +        cx,
 +        BOOL_COMPARISON,
 +        e.span,
 +        message,
 +        "try simplifying it as shown",
 +        conv_hint(hint).to_string(),
 +        applicability,
 +    );
 +}
 +
 +enum Expression {
 +    Bool(bool),
 +    RetBool(bool),
 +    Other,
 +}
 +
 +fn fetch_bool_block(block: &Block<'_>) -> Expression {
 +    match (&*block.stmts, block.expr.as_ref()) {
 +        (&[], Some(e)) => fetch_bool_expr(&**e),
 +        (&[ref e], None) => {
 +            if let StmtKind::Semi(e) = e.kind {
 +                if let ExprKind::Ret(_) = e.kind {
 +                    fetch_bool_expr(e)
 +                } else {
 +                    Expression::Other
 +                }
 +            } else {
 +                Expression::Other
 +            }
 +        },
 +        _ => Expression::Other,
 +    }
 +}
 +
 +fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
 +    match expr.kind {
 +        ExprKind::Block(block, _) => fetch_bool_block(block),
 +        ExprKind::Lit(ref lit_ptr) => {
 +            if let LitKind::Bool(value) = lit_ptr.node {
 +                Expression::Bool(value)
 +            } else {
 +                Expression::Other
 +            }
 +        },
 +        ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) {
 +            Expression::Bool(value) => Expression::RetBool(value),
 +            _ => Expression::Other,
 +        },
 +        _ => Expression::Other,
 +    }
 +}
index fa36d8fb1b30f3f50ee2793d5a9db68b9d70edc9,0000000000000000000000000000000000000000..1b15d29439f780cdee65e26b1dcf002c12aea846
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,55 @@@
-         if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit));
 +use clippy_utils::consts::{self, Constant};
 +use clippy_utils::diagnostics::span_lint;
 +use if_chain::if_chain;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for multiplication by -1 as a form of negation.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more readable to just negate.
 +    ///
 +    /// ### Known problems
 +    /// This only catches integers (for now).
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// x * -1
 +    /// ```
 +    pub NEG_MULTIPLY,
 +    style,
 +    "multiplying integers with `-1`"
 +}
 +
 +declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
 +
 +#[allow(clippy::match_same_arms)]
 +impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref op, left, right) = e.kind {
 +            if BinOpKind::Mul == op.node {
 +                match (&left.kind, &right.kind) {
 +                    (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {},
 +                    (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right),
 +                    (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left),
 +                    _ => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
 +    if_chain! {
 +        if let ExprKind::Lit(ref l) = lit.kind;
++        if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
 +        if cx.typeck_results().expr_ty(exp).is_integral();
 +        then {
 +            span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`");
 +        }
 +    }
 +}
index 0ad616a39d266bf9657b6875a0c05ce793b1348e,0000000000000000000000000000000000000000..0ac27f1cba2262ce1a8c1423678ac787b67d966e
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,172 @@@
-                 if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind {
 +use clippy_utils::diagnostics::span_lint_hir_and_then;
 +use clippy_utils::return_ty;
 +use clippy_utils::source::snippet;
 +use clippy_utils::sugg::DiagnosticBuilderExt;
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::HirIdSet;
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::TyS;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for types with a `fn new() -> Self` method and no
 +    /// implementation of
 +    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
 +    ///
 +    /// ### Why is this bad?
 +    /// The user might expect to be able to use
 +    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
 +    /// type can be constructed without arguments.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// struct Foo(Bar);
 +    ///
 +    /// impl Foo {
 +    ///     fn new() -> Self {
 +    ///         Foo(Bar::new())
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// To fix the lint, add a `Default` implementation that delegates to `new`:
 +    ///
 +    /// ```ignore
 +    /// struct Foo(Bar);
 +    ///
 +    /// impl Default for Foo {
 +    ///     fn default() -> Self {
 +    ///         Foo::new()
 +    ///     }
 +    /// }
 +    /// ```
 +    pub NEW_WITHOUT_DEFAULT,
 +    style,
 +    "`fn new() -> Self` method without `Default` implementation"
 +}
 +
 +#[derive(Clone, Default)]
 +pub struct NewWithoutDefault {
 +    impling_types: Option<HirIdSet>,
 +}
 +
 +impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        if let hir::ItemKind::Impl(hir::Impl {
 +            of_trait: None,
 +            ref generics,
 +            self_ty: impl_self_ty,
 +            items,
 +            ..
 +        }) = item.kind
 +        {
 +            for assoc_item in items {
++                if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
 +                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
 +                    if in_external_macro(cx.sess(), impl_item.span) {
 +                        return;
 +                    }
 +                    if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
 +                        let name = impl_item.ident.name;
 +                        let id = impl_item.hir_id();
 +                        if sig.header.constness == hir::Constness::Const {
 +                            // can't be implemented by default
 +                            return;
 +                        }
 +                        if sig.header.unsafety == hir::Unsafety::Unsafe {
 +                            // can't be implemented for unsafe new
 +                            return;
 +                        }
 +                        if impl_item
 +                            .generics
 +                            .params
 +                            .iter()
 +                            .any(|gen| matches!(gen.kind, hir::GenericParamKind::Type { .. }))
 +                        {
 +                            // when the result of `new()` depends on a type parameter we should not require
 +                            // an
 +                            // impl of `Default`
 +                            return;
 +                        }
 +                        if_chain! {
 +                            if sig.decl.inputs.is_empty();
 +                            if name == sym::new;
 +                            if cx.access_levels.is_reachable(impl_item.def_id);
 +                            let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
 +                            let self_ty = cx.tcx.type_of(self_def_id);
 +                            if TyS::same_type(self_ty, return_ty(cx, id));
 +                            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
 +                            then {
 +                                if self.impling_types.is_none() {
 +                                    let mut impls = HirIdSet::default();
 +                                    cx.tcx.for_each_impl(default_trait_id, |d| {
 +                                        if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
 +                                            if let Some(local_def_id) = ty_def.did.as_local() {
 +                                                impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
 +                                            }
 +                                        }
 +                                    });
 +                                    self.impling_types = Some(impls);
 +                                }
 +
 +                                // Check if a Default implementation exists for the Self type, regardless of
 +                                // generics
 +                                if_chain! {
 +                                    if let Some(ref impling_types) = self.impling_types;
 +                                    if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
 +                                    if let Some(self_local_did) = self_def.did.as_local();
 +                                    let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
 +                                    if impling_types.contains(&self_id);
 +                                    then {
 +                                        return;
 +                                    }
 +                                }
 +
 +                                let generics_sugg = snippet(cx, generics.span, "");
 +                                let self_ty_fmt = self_ty.to_string();
 +                                let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt);
 +                                span_lint_hir_and_then(
 +                                    cx,
 +                                    NEW_WITHOUT_DEFAULT,
 +                                    id,
 +                                    impl_item.span,
 +                                    &format!(
 +                                        "you should consider adding a `Default` implementation for `{}`",
 +                                        self_type_snip
 +                                    ),
 +                                    |diag| {
 +                                        diag.suggest_prepend_item(
 +                                            cx,
 +                                            item.span,
 +                                            "try adding this",
 +                                            &create_new_without_default_suggest_msg(&self_type_snip, &generics_sugg),
 +                                            Applicability::MaybeIncorrect,
 +                                        );
 +                                    },
 +                                );
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn create_new_without_default_suggest_msg(self_type_snip: &str, generics_sugg: &str) -> String {
 +    #[rustfmt::skip]
 +    format!(
 +"impl{} Default for {} {{
 +    fn default() -> Self {{
 +        Self::new()
 +    }}
 +}}", generics_sugg, self_type_snip)
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..374b7bd59649e87db0f8ffbbdb22f1ae0b015309
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,238 @@@
++use clippy_utils::diagnostics::span_lint_and_then;
++use clippy_utils::is_lint_allowed;
++use clippy_utils::source::snippet;
++use clippy_utils::ty::{implements_trait, is_copy};
++use rustc_ast::ImplPolarity;
++use rustc_hir::def_id::DefId;
++use rustc_hir::{FieldDef, Item, ItemKind, Node};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
++use rustc_session::{declare_tool_lint, impl_lint_pass};
++use rustc_span::sym;
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`.
++    ///
++    /// ### Why is this bad?
++    /// Sending the struct to another thread will transfer the ownership to
++    /// the new thread by dropping in the current thread during the transfer.
++    /// This causes soundness issues for non-`Send` fields, as they are also
++    /// dropped and might not be set up to handle this.
++    ///
++    /// See:
++    /// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
++    /// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
++    ///
++    /// ### Known Problems
++    /// Data structures that contain raw pointers may cause false positives.
++    /// They are sometimes safe to be sent across threads but do not implement
++    /// the `Send` trait. This lint has a heuristic to filter out basic cases
++    /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an
++    /// issue if you have a suggestion on how this heuristic can be improved.
++    ///
++    /// ### Example
++    /// ```rust,ignore
++    /// struct ExampleStruct<T> {
++    ///     rc_is_not_send: Rc<String>,
++    ///     unbounded_generic_field: T,
++    /// }
++    ///
++    /// // This impl is unsound because it allows sending `!Send` types through `ExampleStruct`
++    /// unsafe impl<T> Send for ExampleStruct<T> {}
++    /// ```
++    /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
++    /// or specify correct bounds on generic type parameters (`T: Send`).
++    pub NON_SEND_FIELDS_IN_SEND_TY,
++    nursery,
++    "there is field that does not implement `Send` in a `Send` struct"
++}
++
++#[derive(Copy, Clone)]
++pub struct NonSendFieldInSendTy {
++    enable_raw_pointer_heuristic: bool,
++}
++
++impl NonSendFieldInSendTy {
++    pub fn new(enable_raw_pointer_heuristic: bool) -> Self {
++        Self {
++            enable_raw_pointer_heuristic,
++        }
++    }
++}
++
++impl_lint_pass!(NonSendFieldInSendTy => [NON_SEND_FIELDS_IN_SEND_TY]);
++
++impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
++    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
++        let ty_allowed_in_send = if self.enable_raw_pointer_heuristic {
++            ty_allowed_with_raw_pointer_heuristic
++        } else {
++            ty_allowed_without_raw_pointer_heuristic
++        };
++
++        // Checks if we are in `Send` impl item.
++        // We start from `Send` impl instead of `check_field_def()` because
++        // single `AdtDef` may have multiple `Send` impls due to generic
++        // parameters, and the lint is much easier to implement in this way.
++        if_chain! {
++            if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send);
++            if let ItemKind::Impl(hir_impl) = &item.kind;
++            if let Some(trait_ref) = &hir_impl.of_trait;
++            if let Some(trait_id) = trait_ref.trait_def_id();
++            if send_trait == trait_id;
++            if hir_impl.polarity == ImplPolarity::Positive;
++            if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
++            if let self_ty = ty_trait_ref.self_ty();
++            if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
++            then {
++                let mut non_send_fields = Vec::new();
++
++                let hir_map = cx.tcx.hir();
++                for variant in &adt_def.variants {
++                    for field in &variant.fields {
++                        if_chain! {
++                            if let Some(field_hir_id) = field
++                                .did
++                                .as_local()
++                                .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id));
++                            if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id);
++                            if let field_ty = field.ty(cx.tcx, impl_trait_substs);
++                            if !ty_allowed_in_send(cx, field_ty, send_trait);
++                            if let Node::Field(field_def) = hir_map.get(field_hir_id);
++                            then {
++                                non_send_fields.push(NonSendField {
++                                    def: field_def,
++                                    ty: field_ty,
++                                    generic_params: collect_generic_params(cx, field_ty),
++                                })
++                            }
++                        }
++                    }
++                }
++
++                if !non_send_fields.is_empty() {
++                    span_lint_and_then(
++                        cx,
++                        NON_SEND_FIELDS_IN_SEND_TY,
++                        item.span,
++                        &format!(
++                            "this implementation is unsound, as some fields in `{}` are `!Send`",
++                            snippet(cx, hir_impl.self_ty.span, "Unknown")
++                        ),
++                        |diag| {
++                            for field in non_send_fields {
++                                diag.span_note(
++                                    field.def.span,
++                                    &format!("the type of field `{}` is `!Send`", field.def.ident.name),
++                                );
++
++                                match field.generic_params.len() {
++                                    0 => diag.help("use a thread-safe type that implements `Send`"),
++                                    1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)),
++                                    _ => diag.help(&format!(
++                                        "add bounds on type parameter{} `{}` that satisfy `{}: Send`",
++                                        if field.generic_params.len() > 1 { "s" } else { "" },
++                                        field.generic_params_string(),
++                                        snippet(cx, field.def.ty.span, "Unknown"),
++                                    )),
++                                };
++                            }
++                        },
++                    );
++                }
++            }
++        }
++    }
++}
++
++struct NonSendField<'tcx> {
++    def: &'tcx FieldDef<'tcx>,
++    ty: Ty<'tcx>,
++    generic_params: Vec<Ty<'tcx>>,
++}
++
++impl<'tcx> NonSendField<'tcx> {
++    fn generic_params_string(&self) -> String {
++        self.generic_params
++            .iter()
++            .map(ToString::to_string)
++            .collect::<Vec<_>>()
++            .join(", ")
++    }
++}
++
++/// Given a type, collect all of its generic parameters.
++/// Example: `MyStruct<P, Box<Q, R>>` => `vec![P, Q, R]`
++fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
++    ty.walk(cx.tcx)
++        .filter_map(|inner| match inner.unpack() {
++            GenericArgKind::Type(inner_ty) => Some(inner_ty),
++            _ => None,
++        })
++        .filter(|&inner_ty| is_ty_param(inner_ty))
++        .collect()
++}
++
++/// Be more strict when the heuristic is disabled
++fn ty_allowed_without_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool {
++    if implements_trait(cx, ty, send_trait, &[]) {
++        return true;
++    }
++
++    if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) {
++        return true;
++    }
++
++    false
++}
++
++/// Heuristic to allow cases like `Vec<*const u8>`
++fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool {
++    if implements_trait(cx, ty, send_trait, &[]) || is_copy(cx, ty) {
++        return true;
++    }
++
++    // The type is known to be `!Send` and `!Copy`
++    match ty.kind() {
++        ty::Tuple(_) => ty
++            .tuple_fields()
++            .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
++        ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
++        ty::Adt(_, substs) => {
++            if contains_raw_pointer(cx, ty) {
++                // descends only if ADT contains any raw pointers
++                substs.iter().all(|generic_arg| match generic_arg.unpack() {
++                    GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
++                    // Lifetimes and const generics are not solid part of ADT and ignored
++                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
++                })
++            } else {
++                false
++            }
++        },
++        // Raw pointers are `!Send` but allowed by the heuristic
++        ty::RawPtr(_) => true,
++        _ => false,
++    }
++}
++
++/// Checks if the type contains any raw pointers in substs (including nested ones).
++fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
++    for ty_node in target_ty.walk(cx.tcx) {
++        if_chain! {
++            if let GenericArgKind::Type(inner_ty) = ty_node.unpack();
++            if let ty::RawPtr(_) = inner_ty.kind();
++            then {
++                return true;
++            }
++        }
++    }
++
++    false
++}
++
++/// Returns `true` if the type is a type parameter such as `T`.
++fn is_ty_param(target_ty: Ty<'_>) -> bool {
++    matches!(target_ty.kind(), ty::Param(_))
++}
index 34755afdb72f0c1bf011551507cef2e92a03f3c3,0000000000000000000000000000000000000000..0f9e5ada3a8a4e1186a5f5471e9c270272ac440f
mode 100644,000000..100644
--- /dev/null
@@@ -1,83 -1,0 +1,74 @@@
-                 if let BinOpKind::Lt = op.node {
-                     if let BinOpKind::Add = op2.node {
-                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                             "you are trying to use classic C overflow conditions that will fail in Rust");
-                     }
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::SpanlessEq;
 +use if_chain::if_chain;
 +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects classic underflow/overflow checks.
 +    ///
 +    /// ### Why is this bad?
 +    /// Most classic C underflow/overflow checks will fail in
 +    /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = 1;
 +    /// # let b = 2;
 +    /// a + b < a;
 +    /// ```
 +    pub OVERFLOW_CHECK_CONDITIONAL,
 +    complexity,
 +    "overflow checks inspired by C which are likely to panic"
 +}
 +
 +declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]);
 +
++const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust";
++const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust";
++
 +impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
 +    // a + b < a, a > a + b, a < a - b, a - b > a
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
 +        if_chain! {
 +            if let ExprKind::Binary(ref op, first, second) = expr.kind;
 +            if let ExprKind::Binary(ref op2, ident1, ident2) = first.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind;
 +            if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
 +            if cx.typeck_results().expr_ty(ident1).is_integral();
 +            if cx.typeck_results().expr_ty(ident2).is_integral();
 +            then {
-                 if let BinOpKind::Gt = op.node {
-                     if let BinOpKind::Sub = op2.node {
-                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                             "you are trying to use classic C underflow conditions that will fail in Rust");
-                     }
++                if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
++                    span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
 +                }
-                 if let BinOpKind::Gt = op.node {
-                     if let BinOpKind::Add = op2.node {
-                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                             "you are trying to use classic C overflow conditions that will fail in Rust");
-                     }
++                if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
++                    span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
 +                }
 +            }
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Binary(ref op, first, second) = expr.kind;
 +            if let ExprKind::Binary(ref op2, ident1, ident2) = second.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind;
 +            if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
 +            if cx.typeck_results().expr_ty(ident1).is_integral();
 +            if cx.typeck_results().expr_ty(ident2).is_integral();
 +            then {
-                 if let BinOpKind::Lt = op.node {
-                     if let BinOpKind::Sub = op2.node {
-                         span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span,
-                             "you are trying to use classic C underflow conditions that will fail in Rust");
-                     }
++                if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
++                    span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
 +                }
++                if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
++                    span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
 +                }
 +            }
 +        }
 +    }
 +}
index ed2e1f90fa597a76737ddfaf9b38fc7bfd1cebc8,0000000000000000000000000000000000000000..919d4e11e5a060637fb35ab2012a802f80f47aa6
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,74 @@@
-             if !cx.access_levels.is_exported(item.def_id) {
-                 if let Some(false) = self.is_exported.last() {
-                     let span = item.span.with_hi(item.ident.span.hi());
-                     let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
-                     span_lint_and_then(
-                         cx,
-                         REDUNDANT_PUB_CRATE,
-                         span,
-                         &format!("pub(crate) {} inside private module", descr),
-                         |diag| {
-                             diag.span_suggestion(
-                                 item.vis.span,
-                                 "consider using",
-                                 "pub".to_string(),
-                                 Applicability::MachineApplicable,
-                             );
-                         },
-                     );
-                 }
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Item, ItemKind, VisibilityKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for items declared `pub(crate)` that are not crate visible because they
 +    /// are inside a private module.
 +    ///
 +    /// ### Why is this bad?
 +    /// Writing `pub(crate)` is misleading when it's redundant due to the parent
 +    /// module's visibility.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// mod internal {
 +    ///     pub(crate) fn internal_fn() { }
 +    /// }
 +    /// ```
 +    /// This function is not visible outside the module and it can be declared with `pub` or
 +    /// private visibility
 +    /// ```rust
 +    /// mod internal {
 +    ///     pub fn internal_fn() { }
 +    /// }
 +    /// ```
 +    pub REDUNDANT_PUB_CRATE,
 +    nursery,
 +    "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them."
 +}
 +
 +#[derive(Default)]
 +pub struct RedundantPubCrate {
 +    is_exported: Vec<bool>,
 +}
 +
 +impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 +        if let VisibilityKind::Crate { .. } = item.vis.node {
++            if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) {
++                let span = item.span.with_hi(item.ident.span.hi());
++                let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
++                span_lint_and_then(
++                    cx,
++                    REDUNDANT_PUB_CRATE,
++                    span,
++                    &format!("pub(crate) {} inside private module", descr),
++                    |diag| {
++                        diag.span_suggestion(
++                            item.vis.span,
++                            "consider using",
++                            "pub".to_string(),
++                            Applicability::MachineApplicable,
++                        );
++                    },
++                );
 +            }
 +        }
 +
 +        if let ItemKind::Mod { .. } = item.kind {
 +            self.is_exported.push(cx.access_levels.is_exported(item.def_id));
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
 +        if let ItemKind::Mod { .. } = item.kind {
 +            self.is_exported.pop().expect("unbalanced check_item/check_item_post");
 +        }
 +    }
 +}
index 5fd0d1527639e8698fa8760cfaa4385ede1a9d46,0000000000000000000000000000000000000000..cf94c0e97d930f166ec5a2b35da04c789dbc10e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,89 -1,0 +1,89 @@@
-             if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count);
 +use clippy_utils::consts::{constant_context, Constant};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::in_macro;
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
 +    /// - `.to_string()` for `str`
 +    /// - `.clone()` for `String`
 +    /// - `.to_vec()` for `slice`
 +    ///
 +    /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
 +    /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
 +    ///
 +    /// ### Why is this bad?
 +    /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
 +    /// the string is the intention behind this, `clone()` should be used.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").repeat(1);
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = String::from("hello world").clone();
 +    /// }
 +    /// ```
 +    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 ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
 +            if path.ident.name == sym!(repeat);
++            if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
 +            if !in_macro(receiver.span);
 +            then {
 +                let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 +                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_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!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
 +                        Applicability::MachineApplicable,
 +                    );
 +                } else if is_type_diagnostic_item(cx, ty, sym::String) {
 +                    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 b9e317a3cfd03af73f46ea09bc2f6997936fb107,0000000000000000000000000000000000000000..2ca7c18800ee2e362e299393058239cf35324ce3
mode 100644,000000..100644
--- /dev/null
@@@ -1,408 -1,0 +1,235 @@@
- use clippy_utils::diagnostics::span_lint_and_then;
++use clippy_utils::diagnostics::span_lint_and_note;
 +use clippy_utils::source::snippet;
- use clippy_utils::{contains_name, higher, iter_input_pats};
- use rustc_hir::intravisit::FnKind;
- use rustc_hir::{
-     Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind,
-     UnOp,
- };
- use rustc_lint::{LateContext, LateLintPass, LintContext};
- use rustc_middle::lint::in_external_macro;
- use rustc_middle::ty;
- use rustc_session::{declare_lint_pass, declare_tool_lint};
- use rustc_span::source_map::Span;
- use rustc_span::symbol::Symbol;
++use clippy_utils::visitors::is_local_used;
++use rustc_data_structures::fx::FxHashMap;
++use rustc_hir::def::Res;
++use rustc_hir::def_id::LocalDefId;
++use rustc_hir::hir_id::ItemLocalId;
++use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_tool_lint, impl_lint_pass};
++use rustc_span::{Span, Symbol};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, while just changing reference level or mutability.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not much, in fact it's a very common pattern in Rust
 +    /// code. Still, some may opt to avoid it in their code base, they can set this
 +    /// lint to `Warn`.
 +    ///
-     /// ### Known problems
-     /// This lint, as the other shadowing related lints,
-     /// currently only catches very simple patterns.
-     ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// // Bad
 +    /// let x = &x;
 +    ///
 +    /// // Good
 +    /// let y = &x; // use different variable name
 +    /// ```
 +    pub SHADOW_SAME,
 +    restriction,
 +    "rebinding a name to itself, e.g., `let mut x = &mut x`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, while reusing the original value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not too much, in fact it's a common pattern in Rust
 +    /// code. Still, some argue that name shadowing like this hurts readability,
 +    /// because a value may be bound to different things depending on position in
 +    /// the code.
 +    ///
-     /// ### Known problems
-     /// This lint, as the other shadowing related lints,
-     /// currently only catches very simple patterns.
-     ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 2;
 +    /// let x = x + 1;
 +    /// ```
 +    /// use different variable name:
 +    /// ```rust
 +    /// let x = 2;
 +    /// let y = x + 1;
 +    /// ```
 +    pub SHADOW_REUSE,
 +    restriction,
 +    "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for bindings that shadow other bindings already in
 +    /// scope, either without an initialization or with one that does not even use
 +    /// the original value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Name shadowing can hurt readability, especially in
 +    /// large code bases, because it is easy to lose track of the active binding at
 +    /// any place in the code. This can be alleviated by either giving more specific
 +    /// names to bindings or introducing more scopes to contain the bindings.
 +    ///
-     /// ### Known problems
-     /// This lint, as the other shadowing related lints,
-     /// currently only catches very simple patterns. Note that
-     /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level
-     /// for this lint.
-     ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let y = 1;
 +    /// # let z = 2;
 +    /// let x = y;
 +    ///
 +    /// // Bad
 +    /// let x = z; // shadows the earlier binding
 +    ///
 +    /// // Good
 +    /// let w = z; // use different variable name
 +    /// ```
 +    pub SHADOW_UNRELATED,
-     pedantic,
++    restriction,
 +    "rebinding a name without even using the original value"
 +}
 +
- declare_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
++#[derive(Default)]
++pub(crate) struct Shadow {
++    bindings: Vec<FxHashMap<Symbol, Vec<ItemLocalId>>>,
++}
++
++impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Shadow {
-     fn check_fn(
-         &mut self,
-         cx: &LateContext<'tcx>,
-         _: FnKind<'tcx>,
-         decl: &'tcx FnDecl<'_>,
-         body: &'tcx Body<'_>,
-         _: Span,
-         _: HirId,
-     ) {
-         if in_external_macro(cx.sess(), body.value.span) {
++    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
++        let (id, ident) = match pat.kind {
++            PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
++            _ => return,
++        };
++        if ident.span.from_expansion() || ident.span.is_dummy() {
 +            return;
 +        }
-         check_fn(cx, decl, body);
-     }
- }
++        let HirId { owner, local_id } = id;
 +
- fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>) {
-     let mut bindings = Vec::with_capacity(decl.inputs.len());
-     for arg in iter_input_pats(decl, body) {
-         if let PatKind::Binding(.., ident, _) = arg.pat.kind {
-             bindings.push((ident.name, ident.span));
++        // get (or insert) the list of items for this owner and symbol
++        let data = self.bindings.last_mut().unwrap();
++        let items_with_name = data.entry(ident.name).or_default();
++
++        // check other bindings with the same name, most recently seen first
++        for &prev in items_with_name.iter().rev() {
++            if prev == local_id {
++                // repeated binding in an `Or` pattern
++                return;
++            }
++
++            if is_shadow(cx, owner, prev, local_id) {
++                let prev_hir_id = HirId { owner, local_id: prev };
++                lint_shadow(cx, pat, prev_hir_id, ident.span);
++                // only lint against the "nearest" shadowed binding
++                break;
++            }
 +        }
++        // store the binding
++        items_with_name.push(local_id);
 +    }
-     check_expr(cx, &body.value, &mut bindings);
- }
 +
- fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &mut Vec<(Symbol, Span)>) {
-     let len = bindings.len();
-     for stmt in block.stmts {
-         match stmt.kind {
-             StmtKind::Local(local) => check_local(cx, local, bindings),
-             StmtKind::Expr(e) | StmtKind::Semi(e) => check_expr(cx, e, bindings),
-             StmtKind::Item(..) => {},
++    fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
++        let hir = cx.tcx.hir();
++        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
++            self.bindings.push(FxHashMap::default());
 +        }
 +    }
-     if let Some(o) = block.expr {
-         check_expr(cx, o, bindings);
-     }
-     bindings.truncate(len);
- }
 +
- fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &mut Vec<(Symbol, Span)>) {
-     if in_external_macro(cx.sess(), local.span) {
-         return;
-     }
-     if higher::is_from_for_desugar(local) {
-         return;
-     }
-     let Local {
-         pat,
-         ref ty,
-         ref init,
-         span,
-         ..
-     } = *local;
-     if let Some(t) = *ty {
-         check_ty(cx, t, bindings);
-     }
-     if let Some(o) = *init {
-         check_expr(cx, o, bindings);
-         check_pat(cx, pat, Some(o), span, bindings);
-     } else {
-         check_pat(cx, pat, None, span, bindings);
++    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
++        let hir = cx.tcx.hir();
++        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
++            self.bindings.pop();
++        }
 +    }
 +}
 +
- fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool {
-     let var_ty = cx.typeck_results().node_type_opt(pat_id);
-     var_ty.map_or(false, |var_ty| !matches!(var_ty.kind(), ty::Adt(..)))
++fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
++    let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
++    let first_scope = scope_tree.var_scope(first);
++    let second_scope = scope_tree.var_scope(second);
++    scope_tree.is_subscope_of(second_scope, first_scope)
 +}
 +
- fn check_pat<'tcx>(
-     cx: &LateContext<'tcx>,
-     pat: &'tcx Pat<'_>,
-     init: Option<&'tcx Expr<'_>>,
-     span: Span,
-     bindings: &mut Vec<(Symbol, Span)>,
- ) {
-     // TODO: match more stuff / destructuring
-     match pat.kind {
-         PatKind::Binding(.., ident, ref inner) => {
-             let name = ident.name;
-             if is_binding(cx, pat.hir_id) {
-                 let mut new_binding = true;
-                 for tup in bindings.iter_mut() {
-                     if tup.0 == name {
-                         lint_shadow(cx, name, span, pat.span, init, tup.1);
-                         tup.1 = ident.span;
-                         new_binding = false;
-                         break;
-                     }
-                 }
-                 if new_binding {
-                     bindings.push((name, ident.span));
-                 }
-             }
-             if let Some(p) = *inner {
-                 check_pat(cx, p, init, span, bindings);
-             }
-         },
-         PatKind::Struct(_, pfields, _) => {
-             if let Some(init_struct) = init {
-                 if let ExprKind::Struct(_, efields, _) = init_struct.kind {
-                     for field in pfields {
-                         let name = field.ident.name;
-                         let efield = efields
-                             .iter()
-                             .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None });
-                         check_pat(cx, field.pat, efield, span, bindings);
-                     }
-                 } else {
-                     for field in pfields {
-                         check_pat(cx, field.pat, init, span, bindings);
-                     }
-                 }
-             } else {
-                 for field in pfields {
-                     check_pat(cx, field.pat, None, span, bindings);
-                 }
-             }
++fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) {
++    let (lint, msg) = match find_init(cx, pat.hir_id) {
++        Some(expr) if is_self_shadow(cx, pat, expr, shadowed) => {
++            let msg = format!(
++                "`{}` is shadowed by itself in `{}`",
++                snippet(cx, pat.span, "_"),
++                snippet(cx, expr.span, "..")
++            );
++            (SHADOW_SAME, msg)
 +        },
-         PatKind::Tuple(inner, _) => {
-             if let Some(init_tup) = init {
-                 if let ExprKind::Tup(tup) = init_tup.kind {
-                     for (i, p) in inner.iter().enumerate() {
-                         check_pat(cx, p, Some(&tup[i]), p.span, bindings);
-                     }
-                 } else {
-                     for p in inner {
-                         check_pat(cx, p, init, span, bindings);
-                     }
-                 }
-             } else {
-                 for p in inner {
-                     check_pat(cx, p, None, span, bindings);
-                 }
-             }
++        Some(expr) if is_local_used(cx, expr, shadowed) => {
++            let msg = format!(
++                "`{}` is shadowed by `{}` which reuses the original value",
++                snippet(cx, pat.span, "_"),
++                snippet(cx, expr.span, "..")
++            );
++            (SHADOW_REUSE, msg)
 +        },
-         PatKind::Box(inner) => {
-             if let Some(initp) = init {
-                 if let ExprKind::Box(inner_init) = initp.kind {
-                     check_pat(cx, inner, Some(inner_init), span, bindings);
-                 } else {
-                     check_pat(cx, inner, init, span, bindings);
-                 }
-             } else {
-                 check_pat(cx, inner, init, span, bindings);
-             }
++        _ => {
++            let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
++            (SHADOW_UNRELATED, msg)
 +        },
-         PatKind::Ref(inner, _) => check_pat(cx, inner, init, span, bindings),
-         // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
-         _ => (),
-     }
++    };
++    span_lint_and_note(
++        cx,
++        lint,
++        span,
++        &msg,
++        Some(cx.tcx.hir().span(shadowed)),
++        "previous binding is here",
++    );
 +}
 +
- fn lint_shadow<'tcx>(
-     cx: &LateContext<'tcx>,
-     name: Symbol,
-     span: Span,
-     pattern_span: Span,
-     init: Option<&'tcx Expr<'_>>,
-     prev_span: Span,
- ) {
-     if let Some(expr) = init {
-         if is_self_shadow(name, expr) {
-             span_lint_and_then(
-                 cx,
-                 SHADOW_SAME,
-                 span,
-                 &format!(
-                     "`{}` is shadowed by itself in `{}`",
-                     snippet(cx, pattern_span, "_"),
-                     snippet(cx, expr.span, "..")
-                 ),
-                 |diag| {
-                     diag.span_note(prev_span, "previous binding is here");
-                 },
-             );
-         } else if contains_name(name, expr) {
-             span_lint_and_then(
-                 cx,
-                 SHADOW_REUSE,
-                 pattern_span,
-                 &format!(
-                     "`{}` is shadowed by `{}` which reuses the original value",
-                     snippet(cx, pattern_span, "_"),
-                     snippet(cx, expr.span, "..")
-                 ),
-                 |diag| {
-                     diag.span_note(expr.span, "initialization happens here");
-                     diag.span_note(prev_span, "previous binding is here");
-                 },
-             );
-         } else {
-             span_lint_and_then(
-                 cx,
-                 SHADOW_UNRELATED,
-                 pattern_span,
-                 &format!("`{}` is being shadowed", snippet(cx, pattern_span, "_")),
-                 |diag| {
-                     diag.span_note(expr.span, "initialization happens here");
-                     diag.span_note(prev_span, "previous binding is here");
++/// Returns true if the expression is a simple transformation of a local binding such as `&x`
++fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_id: HirId) -> bool {
++    let hir = cx.tcx.hir();
++    let is_direct_binding = hir
++        .parent_iter(pat.hir_id)
++        .map_while(|(_id, node)| match node {
++            Node::Pat(pat) => Some(pat),
++            _ => None,
++        })
++        .all(|pat| matches!(pat.kind, PatKind::Ref(..) | PatKind::Or(_)));
++    if !is_direct_binding {
++        return false;
++    }
++    loop {
++        expr = match expr.kind {
++            ExprKind::Box(e)
++            | ExprKind::AddrOf(_, _, e)
++            | ExprKind::Block(
++                &Block {
++                    stmts: [],
++                    expr: Some(e),
++                    ..
 +                },
-             );
++                _,
++            )
++            | ExprKind::Unary(UnOp::Deref, e) => e,
++            ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
++            _ => break false,
 +        }
-     } else {
-         span_lint_and_then(
-             cx,
-             SHADOW_UNRELATED,
-             span,
-             &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")),
-             |diag| {
-                 diag.span_note(prev_span, "previous binding is here");
-             },
-         );
 +    }
 +}
 +
- fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut Vec<(Symbol, Span)>) {
-     if in_external_macro(cx.sess(), expr.span) {
-         return;
-     }
-     match expr.kind {
-         ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
-             check_expr(cx, e, bindings);
-         },
-         ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
-         // ExprKind::Call
-         // ExprKind::MethodCall
-         ExprKind::Array(v) | ExprKind::Tup(v) => {
-             for e in v {
-                 check_expr(cx, e, bindings);
-             }
-         },
-         ExprKind::If(cond, then, ref otherwise) => {
-             check_expr(cx, cond, bindings);
-             check_expr(cx, then, bindings);
-             if let Some(o) = *otherwise {
-                 check_expr(cx, o, bindings);
-             }
-         },
-         ExprKind::Match(init, arms, _) => {
-             check_expr(cx, init, bindings);
-             let len = bindings.len();
-             for arm in arms {
-                 check_pat(cx, arm.pat, Some(init), arm.pat.span, bindings);
-                 // This is ugly, but needed to get the right type
-                 if let Some(ref guard) = arm.guard {
-                     match guard {
-                         Guard::If(if_expr) => check_expr(cx, if_expr, bindings),
-                         Guard::IfLet(guard_pat, guard_expr) => {
-                             check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings);
-                             check_expr(cx, guard_expr, bindings);
-                         },
-                     }
-                 }
-                 check_expr(cx, arm.body, bindings);
-                 bindings.truncate(len);
-             }
-         },
-         _ => (),
-     }
- }
- fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(Symbol, Span)>) {
-     match ty.kind {
-         TyKind::Slice(sty) => check_ty(cx, sty, bindings),
-         TyKind::Array(fty, ref anon_const) => {
-             check_ty(cx, fty, bindings);
-             check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings);
-         },
-         TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
-         TyKind::Tup(tup) => {
-             for t in tup {
-                 check_ty(cx, t, bindings);
-             }
-         },
-         TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
-         _ => (),
-     }
- }
- fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool {
-     match expr.kind {
-         ExprKind::Box(inner) | ExprKind::AddrOf(_, _, inner) => is_self_shadow(name, inner),
-         ExprKind::Block(block, _) => {
-             block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e))
-         },
-         ExprKind::Unary(op, inner) => (UnOp::Deref == op) && is_self_shadow(name, inner),
-         ExprKind::Path(QPath::Resolved(_, path)) => path_eq_name(name, path),
-         _ => false,
++/// Finds the "init" expression for a pattern: `let <pat> = <init>;` or
++/// `match <init> { .., <pat> => .., .. }`
++fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
++    for (_, node) in cx.tcx.hir().parent_iter(hir_id) {
++        let init = match node {
++            Node::Arm(_) | Node::Pat(_) => continue,
++            Node::Expr(expr) => match expr.kind {
++                ExprKind::Match(e, _, _) => Some(e),
++                _ => None,
++            },
++            Node::Local(local) => local.init,
++            _ => None,
++        };
++        return init;
 +    }
- }
- fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool {
-     !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.name == name
++    None
 +}
index a67fa7922059ce865276fce368d7c5fe4a1d42a4,0000000000000000000000000000000000000000..ef80663d1da41ecdce20d5b885be1482f14b437f
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,88 @@@
-                     let x = const_eval_context.expr(arg);
-                     if let Some(Constant::RawPtr(0)) = x;
 +use clippy_utils::consts::{constant_context, Constant};
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::is_expr_diagnostic_item;
 +use if_chain::if_chain;
 +use rustc_ast::LitKind;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmute calls which would receive a null pointer.
 +    ///
 +    /// ### Why is this bad?
 +    /// Transmuting a null pointer is undefined behavior.
 +    ///
 +    /// ### Known problems
 +    /// Not all cases can be detected at the moment of this writing.
 +    /// For example, variables which hold a null pointer and are then fed to a `transmute`
 +    /// call, aren't detectable yet.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
 +    /// ```
 +    pub TRANSMUTING_NULL,
 +    correctness,
 +    "transmutes from a null pointer to a reference, which is undefined behavior"
 +}
 +
 +declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
 +
 +const LINT_MSG: &str = "transmuting a known null pointer into a reference";
 +
 +impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), expr.span) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(func, [arg]) = expr.kind;
 +            if is_expr_diagnostic_item(cx, func, sym::transmute);
 +
 +            then {
 +                // Catching transmute over constants that resolve to `null`.
 +                let mut const_eval_context = constant_context(cx, cx.typeck_results());
 +                if_chain! {
 +                    if let ExprKind::Path(ref _qpath) = arg.kind;
++                    if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
++                    if x == 0;
 +                    then {
 +                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
 +                    }
 +                }
 +
 +                // Catching:
 +                // `std::mem::transmute(0 as *const i32)`
 +                if_chain! {
 +                    if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
 +                    if let ExprKind::Lit(ref lit) = inner_expr.kind;
 +                    if let LitKind::Int(0, _) = lit.node;
 +                    then {
 +                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
 +                    }
 +                }
 +
 +                // Catching:
 +                // `std::mem::transmute(std::ptr::null::<i32>())`
 +                if_chain! {
 +                    if let ExprKind::Call(func1, []) = arg.kind;
 +                    if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
 +                    then {
 +                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
 +                    }
 +                }
 +
 +                // FIXME:
 +                // Also catch transmutations of variables which are known nulls.
 +                // To do this, MIR const propagation seems to be the better tool.
 +                // Whenever MIR const prop routines are more developed, this will
 +                // become available. As of this writing (25/03/19) it is not yet.
 +            }
 +        }
 +    }
 +}
index 4f50284e941abd1dcaab283b77c0bf24b4acee29,0000000000000000000000000000000000000000..903e62995c61702be4775eb152c9674a5e25486b
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,22 @@@
-     if cx.tcx.is_diagnostic_item(sym::Option, def_id)
-         && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some()
-     {
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::is_ty_param_diagnostic_item;
 +use rustc_hir::{self as hir, def_id::DefId, QPath};
 +use rustc_lint::LateContext;
 +use rustc_span::symbol::sym;
 +
 +use super::OPTION_OPTION;
 +
 +pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
++    if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::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",
 +        );
 +        true
 +    } else {
 +        false
 +    }
 +}
index 1e0447239be99813cb7777c9e929fa600e86c71c,0000000000000000000000000000000000000000..6cbada4c1505b5374758d951ca2df152eec9a4d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,327 -1,0 +1,331 @@@
 +//! Read configurations files.
 +
 +#![allow(clippy::module_name_repetitions)]
 +
 +use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 +use serde::Deserialize;
 +use std::error::Error;
 +use std::path::{Path, PathBuf};
 +use std::{env, fmt, fs, io};
 +
 +/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +pub struct Rename {
 +    pub path: String,
 +    pub rename: String,
 +}
 +
 +/// A single disallowed method, used by the `DISALLOWED_METHOD` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedMethod {
 +    Simple(String),
 +    WithReason { path: String, reason: Option<String> },
 +}
 +
 +/// Conf with parse errors
 +#[derive(Default)]
 +pub struct TryConf {
 +    pub conf: Conf,
 +    pub errors: Vec<String>,
 +}
 +
 +impl TryConf {
 +    fn from_error(error: impl Error) -> Self {
 +        Self {
 +            conf: Conf::default(),
 +            errors: vec![error.to_string()],
 +        }
 +    }
 +}
 +
 +macro_rules! define_Conf {
 +    ($(
 +        $(#[doc = $doc:literal])+
 +        $(#[conf_deprecated($dep:literal)])?
 +        ($name:ident: $ty:ty = $default:expr),
 +    )*) => {
 +        /// Clippy lint configuration
 +        pub struct Conf {
 +            $($(#[doc = $doc])+ pub $name: $ty,)*
 +        }
 +
 +        mod defaults {
 +            $(pub fn $name() -> $ty { $default })*
 +        }
 +
 +        impl Default for Conf {
 +            fn default() -> Self {
 +                Self { $($name: defaults::$name(),)* }
 +            }
 +        }
 +
 +        impl<'de> Deserialize<'de> for TryConf {
 +            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
 +                deserializer.deserialize_map(ConfVisitor)
 +            }
 +        }
 +
 +        #[derive(Deserialize)]
 +        #[serde(field_identifier, rename_all = "kebab-case")]
 +        #[allow(non_camel_case_types)]
 +        enum Field { $($name,)* third_party, }
 +
 +        struct ConfVisitor;
 +
 +        impl<'de> Visitor<'de> for ConfVisitor {
 +            type Value = TryConf;
 +
 +            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                formatter.write_str("Conf")
 +            }
 +
 +            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
 +                let mut errors = Vec::new();
 +                $(let mut $name = None;)*
 +                // could get `Field` here directly, but get `str` first for diagnostics
 +                while let Some(name) = map.next_key::<&str>()? {
 +                    match Field::deserialize(name.into_deserializer())? {
 +                        $(Field::$name => {
 +                            $(errors.push(format!("deprecated field `{}`. {}", name, $dep));)?
 +                            match map.next_value() {
 +                                Err(e) => errors.push(e.to_string()),
 +                                Ok(value) => match $name {
 +                                    Some(_) => errors.push(format!("duplicate field `{}`", name)),
 +                                    None => $name = Some(value),
 +                                }
 +                            }
 +                        })*
 +                        // white-listed; ignore
 +                        Field::third_party => drop(map.next_value::<IgnoredAny>())
 +                    }
 +                }
 +                let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
 +                Ok(TryConf { conf, errors })
 +            }
 +        }
 +
 +        #[cfg(feature = "metadata-collector-lint")]
 +        pub mod metadata {
 +            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 +
 +            macro_rules! wrap_option {
 +                () => (None);
 +                ($x:literal) => (Some($x));
 +            }
 +
 +            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 +                vec![
 +                    $(
 +                        {
 +                            let deprecation_reason = wrap_option!($($dep)?);
 +
 +                            ClippyConfiguration::new(
 +                                stringify!($name),
 +                                stringify!($ty),
 +                                format!("{:?}", super::defaults::$name()),
 +                                concat!($($doc, '\n',)*),
 +                                deprecation_reason,
 +                            )
 +                        },
 +                    )+
 +                ]
 +            }
 +        }
 +    };
 +}
 +
 +define_Conf! {
 +    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
 +    ///
 +    /// Suppress lints whenever the suggested change would cause breakage for other crates.
 +    (avoid_breaking_exported_api: bool = true),
 +    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT.
 +    ///
 +    /// The minimum rust version that the project supports
 +    (msrv: Option<String> = None),
 +    /// Lint: BLACKLISTED_NAME.
 +    ///
 +    /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
 +    (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: u64 = 25),
 +    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
 +    ///
 +    /// Use the Cognitive Complexity lint instead.
 +    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
 +    (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: Vec<String> = [
 +        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
 +        "DirectX",
 +        "ECMAScript",
 +        "GPLv2", "GPLv3",
 +        "GitHub", "GitLab",
 +        "IPv4", "IPv6",
 +        "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
 +        "NaN", "NaNs",
 +        "OAuth", "GraphQL",
 +        "OCaml",
 +        "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
 +        "WebGL",
 +        "TensorFlow",
 +        "TrueType",
 +        "iOS", "macOS", "FreeBSD",
 +        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
 +        "MinGW",
 +        "CamelCase",
 +    ].iter().map(ToString::to_string).collect()),
 +    /// Lint: TOO_MANY_ARGUMENTS.
 +    ///
 +    /// The maximum number of argument a function or method can have
 +    (too_many_arguments_threshold: u64 = 7),
 +    /// Lint: TYPE_COMPLEXITY.
 +    ///
 +    /// The maximum complexity a type can have
 +    (type_complexity_threshold: u64 = 250),
 +    /// Lint: MANY_SINGLE_CHAR_NAMES.
 +    ///
 +    /// The maximum number of single char bindings a scope may have
 +    (single_char_binding_names_threshold: u64 = 4),
 +    /// Lint: BOXED_LOCAL, USELESS_VEC.
 +    ///
 +    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
 +    (too_large_for_stack: u64 = 200),
 +    /// Lint: ENUM_VARIANT_NAMES.
 +    ///
 +    /// The minimum number of enum variants for the lints about variant names to trigger
 +    (enum_variant_name_threshold: u64 = 3),
 +    /// Lint: LARGE_ENUM_VARIANT.
 +    ///
 +    /// The maximum size of an enum's variant to avoid box suggestion
 +    (enum_variant_size_threshold: u64 = 200),
 +    /// Lint: VERBOSE_BIT_MASK.
 +    ///
 +    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
 +    (verbose_bit_mask_threshold: u64 = 1),
 +    /// Lint: DECIMAL_LITERAL_REPRESENTATION.
 +    ///
 +    /// The lower bound for linting decimal literals
 +    (literal_representation_threshold: u64 = 16384),
 +    /// Lint: TRIVIALLY_COPY_PASS_BY_REF.
 +    ///
 +    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
 +    (trivial_copy_size_limit: Option<u64> = None),
 +    /// Lint: LARGE_TYPE_PASS_BY_MOVE.
 +    ///
 +    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
 +    (pass_by_value_size_limit: u64 = 256),
 +    /// Lint: TOO_MANY_LINES.
 +    ///
 +    /// The maximum number of lines a function or method can have
 +    (too_many_lines_threshold: u64 = 100),
 +    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
 +    ///
 +    /// The maximum allowed size for arrays on the stack
 +    (array_size_threshold: u64 = 512_000),
 +    /// Lint: VEC_BOX.
 +    ///
 +    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
 +    (vec_box_size_threshold: u64 = 4096),
 +    /// Lint: TYPE_REPETITION_IN_BOUNDS.
 +    ///
 +    /// The maximum number of bounds a trait can have to be linted
 +    (max_trait_bounds: u64 = 3),
 +    /// Lint: STRUCT_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool fields a struct can have
 +    (max_struct_bools: u64 = 3),
 +    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool parameters a function can have
 +    (max_fn_params_bools: u64 = 3),
 +    /// Lint: WILDCARD_IMPORTS.
 +    ///
 +    /// Whether to allow certain wildcard imports (prelude, super in tests).
 +    (warn_on_all_wildcard_imports: bool = false),
 +    /// Lint: DISALLOWED_METHOD.
 +    ///
 +    /// The list of disallowed methods, written as fully qualified paths.
 +    (disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
 +    /// Lint: DISALLOWED_TYPE.
 +    ///
 +    /// The list of disallowed types, written as fully qualified paths.
 +    (disallowed_types: Vec<String> = Vec::new()),
 +    /// Lint: UNREADABLE_LITERAL.
 +    ///
 +    /// Should the fraction of a decimal be linted to include separators.
 +    (unreadable_literal_lint_fractions: bool = true),
 +    /// Lint: UPPER_CASE_ACRONYMS.
 +    ///
 +    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
 +    (upper_case_acronyms_aggressive: bool = false),
 +    /// Lint: _CARGO_COMMON_METADATA.
 +    ///
 +    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
 +    (cargo_ignore_publish: bool = false),
 +    /// Lint: NONSTANDARD_MACRO_BRACES.
 +    ///
 +    /// Enforce the named macros always use the braces specified.
 +    ///
 +    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
 +    /// is could be used with a full path two `MacroMatcher`s have to be added one with the full path
 +    /// `crate_name::macro_name` and one with just the macro name.
 +    (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
 +    /// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
 +    ///
 +    /// The list of imports to always rename, a fully qualified path followed by the rename.
 +    (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
 +    /// Lint: RESTRICTED_SCRIPTS.
 +    ///
 +    /// The list of unicode scripts allowed to be used in the scope.
 +    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
++    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
++    ///
++    /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
++    (enable_raw_pointer_heuristic_for_send: bool = true),
 +}
 +
 +/// 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 {
 +            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
 +                match fs::metadata(&config_file) {
 +                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
 +                    Err(e) => return Err(e),
 +                    Ok(md) if md.is_dir() => {},
 +                    Ok(_) => return Ok(Some(config_file)),
 +                }
 +            }
 +        }
 +
 +        // If the current directory has no parent, we're done searching.
 +        if !current.pop() {
 +            return Ok(None);
 +        }
 +    }
 +}
 +
 +/// Read the `toml` configuration file.
 +///
 +/// In case of error, the function tries to continue as much as possible.
 +pub fn read(path: &Path) -> TryConf {
 +    let content = match fs::read_to_string(path) {
 +        Err(e) => return TryConf::from_error(e),
 +        Ok(content) => content,
 +    };
 +    toml::from_str(&content).unwrap_or_else(TryConf::from_error)
 +}
index 59c40050522b2182f91c0dc40f9cc054997c3615,0000000000000000000000000000000000000000..9f9edbf258ac277831739b1fe2f0fb549ade8b22
mode 100644,000000..100644
--- /dev/null
@@@ -1,1231 -1,0 +1,1231 @@@
- use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId};
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::higher;
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::match_type;
 +use clippy_utils::{
 +    is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls, path_to_res,
 +    paths, SpanlessEq,
 +};
 +use if_chain::if_chain;
-     BinOpKind, Block, Crate, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty,
-     TyKind, UnOp,
++use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
 +use rustc_ast::visit::FnKind;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::CRATE_HIR_ID;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::{
-     fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
++    BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind,
++    UnOp,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::mir::interpret::ConstValue;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::symbol::{Symbol, SymbolStr};
 +use rustc_span::{BytePos, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use std::borrow::{Borrow, Cow};
 +
 +#[cfg(feature = "metadata-collector-lint")]
 +pub mod metadata_collector;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for various things we like to keep tidy in clippy.
 +    ///
 +    /// ### Why is this bad?
 +    /// We like to pretend we're an example of tidy code.
 +    ///
 +    /// ### Example
 +    /// Wrong ordering of the util::paths constants.
 +    pub CLIPPY_LINTS_INTERNAL,
 +    internal,
 +    "various things that will negatively affect your clippy experience"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Ensures every lint is associated to a `LintPass`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The compiler only knows lints via a `LintPass`. Without
 +    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
 +    /// know the name of the lint.
 +    ///
 +    /// ### Known problems
 +    /// Only checks for lints associated using the
 +    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// declare_lint! { pub LINT_1, ... }
 +    /// declare_lint! { pub LINT_2, ... }
 +    /// declare_lint! { pub FORGOTTEN_LINT, ... }
 +    /// // ...
 +    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
 +    /// // missing FORGOTTEN_LINT
 +    /// ```
 +    pub LINT_WITHOUT_LINT_PASS,
 +    internal,
 +    "declaring a lint without associating it in a LintPass"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
 +    /// variant of the function.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `utils::*` variants also add a link to the Clippy documentation to the
 +    /// warning/error messages.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// cx.span_lint(LINT_NAME, "message");
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::span_lint(cx, LINT_NAME, "message");
 +    /// ```
 +    pub COMPILER_LINT_FUNCTIONS,
 +    internal,
 +    "usage of the lint functions of the compiler instead of the utils::* variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.outer().expn_data()` and suggests to use
 +    /// the `cx.outer_expn_data()`
 +    ///
 +    /// ### Why is this bad?
 +    /// `cx.outer_expn_data()` is faster and more concise.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer().expn_data()
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer_expn_data()
 +    /// ```
 +    pub OUTER_EXPN_EXPN_DATA,
 +    internal,
 +    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Not an actual lint. This lint is only meant for testing our customized internal compiler
 +    /// error message by calling `panic`.
 +    ///
 +    /// ### Why is this bad?
 +    /// ICE in large quantities can damage your teeth
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// 🍦🍦🍦🍦🍦
 +    /// ```
 +    pub PRODUCE_ICE,
 +    internal,
 +    "this message should not appear anywhere as we ICE before and don't emit the lint"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for cases of an auto-generated lint without an updated description,
 +    /// i.e. `default lint description`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Indicates that the lint is not finished.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
 +    /// ```
 +    pub DEFAULT_LINT,
 +    internal,
 +    "found 'default lint description' in a lint declaration"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lints `span_lint_and_then` function calls, where the
 +    /// closure argument has only one statement and that statement is a method
 +    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
 +    /// span), `help` or `note`.
 +    ///
 +    /// These usages of `span_lint_and_then` should be replaced with one of the
 +    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
 +    /// `span_lint_and_note`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the wrapper `span_lint_and_*` functions, is more
 +    /// convenient, readable and less error prone.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_suggestion(
 +    ///         expr.span,
 +    ///         help_msg,
 +    ///         sugg.to_string(),
 +    ///         Applicability::MachineApplicable,
 +    ///     );
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_help(expr.span, help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.help(help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_note(expr.span, note_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.note(note_msg);
 +    /// });
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     TEST_LINT,
 +    ///     expr.span,
 +    ///     lint_msg,
 +    ///     help_msg,
 +    ///     sugg.to_string(),
 +    ///     Applicability::MachineApplicable,
 +    /// );
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
 +    /// ```
 +    pub COLLAPSIBLE_SPAN_LINT_CALLS,
 +    internal,
 +    "found collapsible `span_lint_and_then` calls"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `utils::match_type()` on a type diagnostic item
 +    /// and suggests to use `utils::is_type_diagnostic_item()` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `utils::is_type_diagnostic_item()` does not require hardcoded paths.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// utils::match_type(cx, ty, &paths::VEC)
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
 +    /// ```
 +    pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    internal,
 +    "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks the paths module for invalid paths.
 +    ///
 +    /// ### Why is this bad?
 +    /// It indicates a bug in the code.
 +    ///
 +    /// ### Example
 +    /// None.
 +    pub INVALID_PATHS,
 +    internal,
 +    "invalid path"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for interning symbols that have already been pre-interned and defined as constants.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster and easier to use the symbol constant.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// let _ = sym!(f32);
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// let _ = sym::f32;
 +    /// ```
 +    pub INTERNING_DEFINED_SYMBOL,
 +    internal,
 +    "interning a symbol that is pre-interned and defined as a constant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary conversion from Symbol to a string.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster use symbols directly intead of strings.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// symbol.as_str() == "clippy";
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// symbol == sym::clippy;
 +    /// ```
 +    pub UNNECESSARY_SYMBOL_STR,
 +    internal,
 +    "unnecessary conversion between Symbol and string"
 +}
 +
 +declare_clippy_lint! {
 +    /// Finds unidiomatic usage of `if_chain!`
 +    pub IF_CHAIN_STYLE,
 +    internal,
 +    "non-idiomatic `if_chain!` usage"
 +}
 +
 +declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 +
 +impl EarlyLintPass for ClippyLintsInternal {
-     fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
++    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
 +        if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
 +            if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
 +                if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
 +                    if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
 +                        let mut last_name: Option<SymbolStr> = None;
 +                        for item in 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 is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
 +            return;
 +        }
 +
 +        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
 +            if is_lint_ref_type(cx, ty) {
 +                let expr = &cx.tcx.hir().body(body_id).value;
 +                if_chain! {
 +                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind;
 +                    if let ExprKind::Struct(_, fields, _) = inner_exp.kind;
 +                    let field = fields
 +                        .iter()
 +                        .find(|f| f.ident.as_str() == "desc")
 +                        .expect("lints must have a description field");
 +                    if let ExprKind::Lit(Spanned {
 +                        node: LitKind::Str(ref sym, _),
 +                        ..
 +                    }) = field.expr.kind;
 +                    if sym.as_str() == "default lint description";
 +
 +                    then {
 +                        span_lint(
 +                            cx,
 +                            DEFAULT_LINT,
 +                            item.span,
 +                            &format!("the lint `{}` has the default lint description", item.ident.name),
 +                        );
 +                    }
 +                }
 +                self.declared_lints.insert(item.ident.name, item.span);
 +            }
 +        } else if is_expn_of(item.span, "impl_lint_pass").is_some()
 +            || is_expn_of(item.span, "declare_lint_pass").is_some()
 +        {
 +            if let hir::ItemKind::Impl(hir::Impl {
 +                of_trait: None,
 +                items: impl_item_refs,
 +                ..
 +            }) = item.kind
 +            {
 +                let mut collector = LintCollector {
 +                    output: &mut self.registered_lints,
 +                    cx,
 +                };
 +                let body_id = cx.tcx.hir().body_owned_by(
 +                    impl_item_refs
 +                        .iter()
 +                        .find(|iiref| iiref.ident.as_str() == "get_lints")
 +                        .expect("LintPass needs to implement get_lints")
 +                        .id
 +                        .hir_id(),
 +                );
 +                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
 +            }
 +        }
 +    }
 +
-     fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
++    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
 +        if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
 +            return;
 +        }
 +
 +        for (lint_name, &lint_span) in &self.declared_lints {
 +            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
 +            // file points to "<rustc macros>".
 +            // `compiletest-rs` thinks that's an error in a different file and
 +            // just ignores it. This causes the test in compile-fail/lint_pass
 +            // not able to capture the error.
 +            // Therefore, we need to climb the macro expansion tree and find the
 +            // actual span that invoked `declare_tool_lint!`:
 +            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
 +
 +            if !self.registered_lints.contains(lint_name) {
 +                span_lint(
 +                    cx,
 +                    LINT_WITHOUT_LINT_PASS,
 +                    lint_span,
 +                    &format!("the lint `{}` is not added to any `LintPass`", lint_name),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
 +    if let TyKind::Rptr(
 +        _,
 +        MutTy {
 +            ty: inner,
 +            mutbl: Mutability::Not,
 +        },
 +    ) = ty.kind
 +    {
 +        if let TyKind::Path(ref path) = inner.kind {
 +            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
 +                return match_def_path(cx, def_id, &paths::LINT);
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +struct LintCollector<'a, 'tcx> {
 +    output: &'a mut FxHashSet<Symbol>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
 +        if path.segments.len() == 1 {
 +            self.output.insert(path.segments[0].ident.name);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +}
 +
 +#[derive(Clone, Default)]
 +pub struct CompilerLintFunctions {
 +    map: FxHashMap<&'static str, &'static str>,
 +}
 +
 +impl CompilerLintFunctions {
 +    #[must_use]
 +    pub fn new() -> Self {
 +        let mut map = FxHashMap::default();
 +        map.insert("span_lint", "utils::span_lint");
 +        map.insert("struct_span_lint", "utils::span_lint");
 +        map.insert("lint", "utils::span_lint");
 +        map.insert("span_lint_note", "utils::span_lint_and_note");
 +        map.insert("span_lint_help", "utils::span_lint_and_help");
 +        Self { map }
 +    }
 +}
 +
 +impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
 +            let fn_name = path.ident;
 +            if let Some(sugg) = self.map.get(&*fn_name.as_str());
 +            let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +            if match_type(cx, ty, &paths::EARLY_CONTEXT)
 +                || match_type(cx, ty, &paths::LATE_CONTEXT);
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    COMPILER_LINT_FUNCTIONS,
 +                    path.ident.span,
 +                    "usage of a compiler lint function",
 +                    None,
 +                    &format!("please use the Clippy variant of this function: `{}`", sugg),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
 +
 +impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
 +            return;
 +        }
 +
 +        let (method_names, arg_lists, spans) = method_calls(expr, 2);
 +        let 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 = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +            if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    OUTER_EXPN_EXPN_DATA,
 +                    spans[1].with_hi(expr.span.hi()),
 +                    "usage of `outer_expn().expn_data()`",
 +                    "try",
 +                    "outer_expn_data()".to_string(),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
 +
 +impl EarlyLintPass for ProduceIce {
 +    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
 +        assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
 +    }
 +}
 +
 +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
 +        FnKind::Closure(..) => false,
 +    }
 +}
 +
 +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(func, and_then_args) = expr.kind;
 +            if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
 +            if and_then_args.len() == 5;
 +            if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
 +            let body = cx.tcx.hir().body(*body_id);
 +            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(ps, _, span_call_args, _) = &only_expr.kind;
 +            then {
 +                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
 +                let mut sle = SpanlessEq::new(cx).deny_side_effects();
 +                match &*ps.ident.as_str() {
 +                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
 +                    },
 +                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
 +                    },
 +                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
 +                    },
 +                    "help" => {
 +                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
 +                    }
 +                    "note" => {
 +                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
 +                    }
 +                    _  => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct AndThenSnippets<'a> {
 +    cx: Cow<'a, str>,
 +    lint: Cow<'a, str>,
 +    span: Cow<'a, str>,
 +    msg: Cow<'a, str>,
 +}
 +
 +fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
 +    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
 +    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
 +    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
 +    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
 +
 +    AndThenSnippets {
 +        cx: cx_snippet,
 +        lint: lint_snippet,
 +        span: span_snippet,
 +        msg: msg_snippet,
 +    }
 +}
 +
 +struct SpanSuggestionSnippets<'a> {
 +    help: Cow<'a, str>,
 +    sugg: Cow<'a, str>,
 +    applicability: Cow<'a, str>,
 +}
 +
 +fn span_suggestion_snippets<'a, 'hir>(
 +    cx: &LateContext<'_>,
 +    span_call_args: &'hir [Expr<'hir>],
 +) -> SpanSuggestionSnippets<'a> {
 +    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
 +    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
 +
 +    SpanSuggestionSnippets {
 +        help: help_snippet,
 +        sugg: sugg_snippet,
 +        applicability: applicability_snippet,
 +    }
 +}
 +
 +fn suggest_suggestion(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
 +) {
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            span_suggestion_snippets.help,
 +            span_suggestion_snippets.sugg,
 +            span_suggestion_snippets.applicability
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_help(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    help: &str,
 +    with_span: bool,
 +) {
 +    let option_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_help({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            &option_span,
 +            help
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_note(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    note: &str,
 +    with_span: bool,
 +) {
 +    let note_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collspible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_note({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            note_span,
 +            note
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            // Check if this is a call to utils::match_type()
 +            if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
 +            if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
 +            // Extract the path to the matched type
 +            if let Some(segments) = path_to_matched_type(cx, ty_path);
 +            let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
 +            if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
 +            // Check if the matched type is a diagnostic item
 +            let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
 +            if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
 +            then {
 +                // TODO: check paths constants from external crates.
 +                let cx_snippet = snippet(cx, context.span, "_");
 +                let ty_snippet = snippet(cx, ty.span, "_");
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +                    expr.span,
 +                    "usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
 +                    "try",
 +                    format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
 +    use rustc_hir::ItemKind;
 +
 +    match &expr.kind {
 +        ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
 +        ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
 +            Res::Local(hir_id) => {
 +                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
 +                if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
 +                    if let Some(init) = local.init {
 +                        return path_to_matched_type(cx, init);
 +                    }
 +                }
 +            },
 +            Res::Def(DefKind::Const | DefKind::Static, def_id) => {
 +                if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
 +                    if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
 +                        let body = cx.tcx.hir().body(body_id);
 +                        return path_to_matched_type(cx, &body.value);
 +                    }
 +                }
 +            },
 +            _ => {},
 +        },
 +        ExprKind::Array(exprs) => {
 +            let segments: Vec<SymbolStr> = exprs
 +                .iter()
 +                .filter_map(|expr| {
 +                    if let ExprKind::Lit(lit) = &expr.kind {
 +                        if let LitKind::Str(sym, _) = lit.node {
 +                            return Some(sym.as_str());
 +                        }
 +                    }
 +
 +                    None
 +                })
 +                .collect();
 +
 +            if segments.len() == exprs.len() {
 +                return Some(segments);
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    None
 +}
 +
 +// This is not a complete resolver for paths. It works on all the paths currently used in the paths
 +// module.  That's all it does and all it needs to do.
 +pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
 +    if path_to_res(cx, path) != Res::Err {
 +        return true;
 +    }
 +
 +    // Some implementations can't be found by `path_to_res`, particularly inherent
 +    // implementations of native types. Check lang items.
 +    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
 +    let lang_items = cx.tcx.lang_items();
 +    for item_def_id in lang_items.items().iter().flatten() {
 +        let lang_item_path = cx.get_def_path(*item_def_id);
 +        if path_syms.starts_with(&lang_item_path) {
 +            if let [item] = &path_syms[lang_item_path.len()..] {
 +                for child in cx.tcx.item_children(*item_def_id) {
 +                    if child.ident.name == *item {
 +                        return true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let local_def_id = &cx.tcx.parent_module(item.hir_id());
 +        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
 +        if_chain! {
 +            if mod_name.as_str() == "paths";
 +            if let hir::ItemKind::Const(ty, body_id) = item.kind;
 +            let ty = hir_ty_to_ty(cx.tcx, ty);
 +            if let ty::Array(el_ty, _) = &ty.kind();
 +            if let ty::Ref(_, el_ty, _) = &el_ty.kind();
 +            if el_ty.is_str();
 +            let body = cx.tcx.hir().body(body_id);
 +            let typeck_results = cx.tcx.typeck_body(body_id);
 +            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value);
 +            let path: Vec<&str> = path.iter().map(|x| {
 +                    if let Constant::Str(s) = x {
 +                        s.as_str()
 +                    } else {
 +                        // We checked the type of the constant above
 +                        unreachable!()
 +                    }
 +                }).collect();
 +            if !check_path(cx, &path[..]);
 +            then {
 +                span_lint(cx, INVALID_PATHS, item.span, "invalid path");
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Default)]
 +pub struct InterningDefinedSymbol {
 +    // Maps the symbol value to the constant DefId.
 +    symbol_map: FxHashMap<u32, DefId>,
 +}
 +
 +impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
 +
 +impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
++    fn check_crate(&mut self, cx: &LateContext<'_>) {
 +        if !self.symbol_map.is_empty() {
 +            return;
 +        }
 +
 +        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
 +            if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
 +                for item in cx.tcx.item_children(def_id).iter() {
 +                    if_chain! {
 +                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
 +                        let ty = cx.tcx.type_of(item_def_id);
 +                        if match_type(cx, ty, &paths::SYMBOL);
 +                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
 +                        if let Ok(value) = value.to_u32();
 +                        then {
 +                            self.symbol_map.insert(value, item_def_id);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(func, [arg]) = &expr.kind;
 +            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
 +            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
 +            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
 +            let value = Symbol::intern(&arg).as_u32();
 +            if let Some(&def_id) = self.symbol_map.get(&value);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    INTERNING_DEFINED_SYMBOL,
 +                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
 +                    "interning a defined symbol",
 +                    "try",
 +                    cx.tcx.def_path_str(def_id),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +        if let ExprKind::Binary(op, left, right) = expr.kind {
 +            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
 +                let data = [
 +                    (left, self.symbol_str_expr(left, cx)),
 +                    (right, self.symbol_str_expr(right, cx)),
 +                ];
 +                match data {
 +                    // both operands are a symbol string
 +                    [(_, Some(left)), (_, Some(right))] => {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            UNNECESSARY_SYMBOL_STR,
 +                            expr.span,
 +                            "unnecessary `Symbol` to string conversion",
 +                            "try",
 +                            format!(
 +                                "{} {} {}",
 +                                left.as_symbol_snippet(cx),
 +                                op.node.as_str(),
 +                                right.as_symbol_snippet(cx),
 +                            ),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                    // one of the operands is a symbol string
 +                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
 +                        // creating an owned string for comparison
 +                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                UNNECESSARY_SYMBOL_STR,
 +                                expr.span,
 +                                "unnecessary string allocation",
 +                                "try",
 +                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    },
 +                    // nothing found
 +                    [(_, None), (_, None)] => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl InterningDefinedSymbol {
 +    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
 +        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
 +        static SYMBOL_STR_PATHS: &[&[&str]] = &[
 +            &paths::SYMBOL_AS_STR,
 +            &paths::SYMBOL_TO_IDENT_STRING,
 +            &paths::TO_STRING_METHOD,
 +        ];
 +        // SymbolStr might be de-referenced: `&*symbol.as_str()`
 +        let call = if_chain! {
 +            if let ExprKind::AddrOf(_, _, e) = expr.kind;
 +            if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
 +            then { e } else { expr }
 +        };
 +        if_chain! {
 +            // is a method call
 +            if let ExprKind::MethodCall(_, _, [item], _) = call.kind;
 +            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
 +            let ty = cx.typeck_results().expr_ty(item);
 +            // ...on either an Ident or a Symbol
 +            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
 +                Some(false)
 +            } else if match_type(cx, ty, &paths::IDENT) {
 +                Some(true)
 +            } else {
 +                None
 +            };
 +            // ...which converts it to a string
 +            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
 +            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
 +            then {
 +                let is_to_owned = path.last().unwrap().ends_with("string");
 +                return Some(SymbolStrExpr::Expr {
 +                    item,
 +                    is_ident,
 +                    is_to_owned,
 +                });
 +            }
 +        }
 +        // is a string constant
 +        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
 +            let value = Symbol::intern(&s).as_u32();
 +            // ...which matches a symbol constant
 +            if let Some(&def_id) = self.symbol_map.get(&value) {
 +                return Some(SymbolStrExpr::Const(def_id));
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +enum SymbolStrExpr<'tcx> {
 +    /// a string constant with a corresponding symbol constant
 +    Const(DefId),
 +    /// a "symbol to string" expression like `symbol.as_str()`
 +    Expr {
 +        /// part that evaluates to `Symbol` or `Ident`
 +        item: &'tcx Expr<'tcx>,
 +        is_ident: bool,
 +        /// whether an owned `String` is created like `to_ident_string()`
 +        is_to_owned: bool,
 +    },
 +}
 +
 +impl<'tcx> SymbolStrExpr<'tcx> {
 +    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
 +    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
 +        match *self {
 +            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
 +            Self::Expr { item, is_ident, .. } => {
 +                let mut snip = snippet(cx, item.span.source_callsite(), "..");
 +                if is_ident {
 +                    // get `Ident.name`
 +                    snip.to_mut().push_str(".name");
 +                }
 +                snip
 +            },
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
 +        let (local, after, if_chain_span) = if_chain! {
 +            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
 +            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
 +            then { (local, after, if_chain_span) } else { return }
 +        };
 +        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be above the `if_chain!`",
 +            );
 +        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be inside `then { .. }`",
 +            );
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
 +            (cond, then, r#else.is_some())
 +        } else {
 +            return;
 +        };
 +        let then_block = match then.kind {
 +            ExprKind::Block(block, _) => block,
 +            _ => return,
 +        };
 +        let if_chain_span = is_expn_of(expr.span, "if_chain");
 +        if !els {
 +            check_nested_if_chains(cx, expr, then_block, if_chain_span);
 +        }
 +        let if_chain_span = match if_chain_span {
 +            None => return,
 +            Some(span) => span,
 +        };
 +        // check for `if a && b;`
 +        if_chain! {
 +            if let ExprKind::Binary(op, _, _) = cond.kind;
 +            if op.node == BinOpKind::And;
 +            if cx.sess().source_map().is_multiline(cond.span);
 +            then {
 +                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
 +            }
 +        }
 +        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
 +            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
 +        {
 +            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
 +        }
 +    }
 +}
 +
 +fn check_nested_if_chains(
 +    cx: &LateContext<'_>,
 +    if_expr: &Expr<'_>,
 +    then_block: &Block<'_>,
 +    if_chain_span: Option<Span>,
 +) {
 +    #[rustfmt::skip]
 +    let (head, tail) = match *then_block {
 +        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
 +        Block {
 +            stmts: &[
 +                ref head @ ..,
 +                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
 +            ],
 +            ..
 +        } => (head, tail),
 +        _ => return,
 +    };
 +    if_chain! {
 +        if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
 +        let sm = cx.sess().source_map();
 +        if head
 +            .iter()
 +            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
 +        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
 +        then {} else { return }
 +    }
 +    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
 +        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
 +        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
 +        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
 +        _ => return,
 +    };
 +    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
 +        let (span, msg) = match head {
 +            [] => return,
 +            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
 +            [a, .., b] => (
 +                a.span.to(b.span),
 +                "these `let` statements can also be in the `if_chain!`",
 +            ),
 +        };
 +        diag.span_help(span, msg);
 +    });
 +}
 +
 +fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
 +    cx.tcx
 +        .hir()
 +        .parent_iter(hir_id)
 +        .find(|(_, node)| {
 +            #[rustfmt::skip]
 +            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
 +        })
 +        .map_or(false, |(id, _)| {
 +            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
 +        })
 +}
 +
 +/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
 +/// of the `then {..}` portion of an `if_chain!`
 +fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
 +    let span = if let [stmt, ..] = stmts {
 +        stmt.span
 +    } else if let Some(expr) = expr {
 +        expr.span
 +    } else {
 +        // empty `then {}`
 +        return true;
 +    };
 +    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
 +}
 +
 +/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
 +fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
 +    let mut span = local.pat.span;
 +    if let Some(init) = local.init {
 +        span = span.to(init.span);
 +    }
 +    span.adjust(if_chain_span.ctxt().outer_expn());
 +    let sm = cx.sess().source_map();
 +    let span = sm.span_extend_to_prev_str(span, "let", false);
 +    let span = sm.span_extend_to_next_char(span, ';', false);
 +    Span::new(
 +        span.lo() - BytePos(3),
 +        span.hi() + BytePos(1),
 +        span.ctxt(),
 +        span.parent(),
 +    )
 +}
index b29ced28ac491dd662c0b5fe595681d69bea2307,0000000000000000000000000000000000000000..e0746ce4d8121b115f1da360d5b2e9756aaa3c06
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,65 @@@
-             if let BinOpKind::Div = op.node;
 +use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::diagnostics::span_lint_and_help;
 +use if_chain::if_chain;
 +use rustc_hir::{BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `0.0 / 0.0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's less readable than `f32::NAN` or `f64::NAN`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let nan = 0.0f32 / 0.0;
 +    ///
 +    /// // Good
 +    /// let nan = f32::NAN;
 +    /// ```
 +    pub ZERO_DIVIDED_BY_ZERO,
 +    complexity,
 +    "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`"
 +}
 +
 +declare_lint_pass!(ZeroDiv => [ZERO_DIVIDED_BY_ZERO]);
 +
 +impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // check for instances of 0.0/0.0
 +        if_chain! {
 +            if let ExprKind::Binary(ref op, left, right) = expr.kind;
++            if op.node == BinOpKind::Div;
 +            // TODO - constant_simple does not fold many operations involving floats.
 +            // That's probably fine for this lint - it's pretty unlikely that someone would
 +            // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
 +            if let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left);
 +            if let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right);
 +            if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
 +            if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
 +            then {
 +                // since we're about to suggest a use of f32::NAN or f64::NAN,
 +                // match the precision of the literals that are given.
 +                let float_type = match (lhs_value, rhs_value) {
 +                    (Constant::F64(_), _)
 +                    | (_, Constant::F64(_)) => "f64",
 +                    _ => "f32"
 +                };
 +                span_lint_and_help(
 +                    cx,
 +                    ZERO_DIVIDED_BY_ZERO,
 +                    expr.span,
 +                    "constant division of `0.0` with `0.0` will always result in NaN",
 +                    None,
 +                    &format!(
 +                        "consider using `{}::NAN` if you would like a constant representing NaN",
 +                        float_type,
 +                    ),
 +                );
 +            }
 +        }
 +    }
 +}
index 00123fdba24903e54f089b9043114155b54ac0f4,0000000000000000000000000000000000000000..c47aa9170e547c597711785aae6df8d83dc74844
mode 100644,000000..100644
--- /dev/null
@@@ -1,2109 -1,0 +1,2118 @@@
- #[allow(clippy::shadow_unrelated)] // false positive #6563
 +#![feature(box_patterns)]
 +#![feature(in_band_lifetimes)]
 +#![feature(iter_zip)]
 +#![feature(rustc_private)]
 +#![feature(control_flow_enum)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
 +// warn on the same lints as `clippy_lints`
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +pub mod sym_helper;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
 +pub mod camel_case;
 +pub mod comparisons;
 +pub mod consts;
 +pub mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +pub mod msrvs;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod qualify_min_const_fn;
 +pub mod source;
 +pub mod sugg;
 +pub mod ty;
 +pub mod usage;
 +pub mod visitors;
 +
 +pub use self::attrs::*;
 +pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
 +use rustc_data_structures::unhash::UnhashMap;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 +use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 +use rustc_hir::{
 +    def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
 +    ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat,
 +    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
 +};
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::exports::Export;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::hir::place::PlaceBase;
 +use rustc_middle::ty as rustc_ty;
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::binding::BindingMode;
 +use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
 +use rustc_semver::RustcVersion;
 +use rustc_session::Session;
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::original_sp;
 +use rustc_span::sym;
 +use rustc_span::symbol::{kw, Symbol};
 +use rustc_span::{Span, DUMMY_SP};
 +use rustc_target::abi::Integer;
 +
 +use crate::consts::{constant, Constant};
 +use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
 +
 +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
 +    if let Ok(version) = RustcVersion::parse(msrv) {
 +        return Some(version);
 +    } else if let Some(sess) = sess {
 +        if let Some(span) = span {
 +            sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
 +        }
 +    }
 +    None
 +}
 +
 +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
 +    msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
 +}
 +
 +#[macro_export]
 +macro_rules! extract_msrv_attr {
 +    (LateContext) => {
 +        extract_msrv_attr!(@LateContext, ());
 +    };
 +    (EarlyContext) => {
 +        extract_msrv_attr!(@EarlyContext);
 +    };
 +    (@$context:ident$(, $call:tt)?) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
 +            use $crate::get_unique_inner_attr;
 +            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
 +                Some(msrv_attr) => {
 +                    if let Some(msrv) = msrv_attr.value_str() {
 +                        self.msrv = $crate::parse_msrv(
 +                            &msrv.to_string(),
 +                            Some(cx.sess$($call)?),
 +                            Some(msrv_attr.span),
 +                        );
 +                    } else {
 +                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
 +                    }
 +                },
 +                _ => (),
 +            }
 +        }
 +    };
 +}
 +
 +/// Returns `true` if the two spans come from differing expansions (i.e., one is
 +/// from a macro and one isn't).
 +#[must_use]
 +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
 +    rhs.ctxt() != lhs.ctxt()
 +}
 +
 +/// If the given expression is a local binding, find the initializer expression.
 +/// If that initializer expression is another local binding, find its initializer again.
 +/// This process repeats as long as possible (but usually no more than once). Initializer
 +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
 +/// instead.
 +///
 +/// Examples:
 +/// ```ignore
 +/// let abc = 1;
 +/// //        ^ output
 +/// let def = abc;
 +/// dbg!(def)
 +/// //   ^^^ input
 +///
 +/// // or...
 +/// let abc = 1;
 +/// let def = abc + 2;
 +/// //        ^^^^^^^ output
 +/// dbg!(def)
 +/// //   ^^^ input
 +/// ```
 +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
 +    while let Some(init) = path_to_local(expr)
 +        .and_then(|id| find_binding_init(cx, id))
 +        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
 +    {
 +        expr = init;
 +    }
 +    expr
 +}
 +
 +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
 +/// By only considering immutable bindings, we guarantee that the returned expression represents the
 +/// value of the binding wherever it is referenced.
 +///
 +/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
 +/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
 +/// canonical binding `HirId`.
 +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
 +    let hir = cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::Binding(pat)) = hir.find(hir_id);
 +        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
 +        let parent = hir.get_parent_node(hir_id);
 +        if let Some(Node::Local(local)) = hir.find(parent);
 +        then {
 +            return local.init;
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns `true` if the given `NodeId` is inside a constant context
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// if in_constant(cx, expr.hir_id) {
 +///     // Do something
 +/// }
 +/// ```
 +pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
 +    let parent_id = cx.tcx.hir().get_parent_item(id);
 +    match cx.tcx.hir().get(parent_id) {
 +        Node::Item(&Item {
 +            kind: ItemKind::Const(..) | ItemKind::Static(..),
 +            ..
 +        })
 +        | Node::TraitItem(&TraitItem {
 +            kind: TraitItemKind::Const(..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Const(..),
 +            ..
 +        })
 +        | Node::AnonConst(_) => true,
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(ref sig, ..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(ref sig, _),
 +            ..
 +        }) => sig.header.constness == Constness::Const,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if a `QPath` resolves to a constructor of a `LangItem`.
 +/// For example, use this to check whether a function call or a pattern is `Some(..)`.
 +pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool {
 +    if let QPath::Resolved(_, path) = qpath {
 +        if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
 +            if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
 +                return cx.tcx.parent(ctor_id) == Some(item_id);
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// 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
 +    }
 +}
 +
 +pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
 +    matches!(
 +        expr.kind,
 +        ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr: None,
 +                ..
 +            },
 +            _
 +        ) | ExprKind::Tup([])
 +    )
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild(pat: &Pat<'_>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// Checks if the first type parameter is a lang item.
 +pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| {
 +                cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
 +            })
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Checks if the first type parameter is a diagnostic item.
 +pub fn is_ty_param_diagnostic_item(
 +    cx: &LateContext<'_>,
 +    qpath: &QPath<'tcx>,
 +    item: Symbol,
 +) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +/// This is a deprecated function, consider using [`is_trait_method`].
 +pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
 +    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +    let trt_id = cx.tcx.trait_of_item(def_id);
 +    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 +}
 +
 +/// Checks if a method is defined in an impl of a diagnostic item
 +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +        if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +            return cx.tcx.is_diagnostic_item(diag_item, adt.did);
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if a method is in a diagnostic item trait
 +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
 +        return cx.tcx.is_diagnostic_item(diag_item, trait_did);
 +    }
 +    false
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    cx.typeck_results()
 +        .type_dependent_def_id(expr.hir_id)
 +        .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 +}
 +
 +/// Checks if the given expression is a path referring an item on the trait
 +/// that is marked with the given diagnostic item.
 +///
 +/// For checking method call expressions instead of path expressions, use
 +/// [`is_trait_method`].
 +///
 +/// For example, this can be used to find if an expression like `u64::default`
 +/// refers to an item of the trait `Default`, which is associated with the
 +/// `diag_item` of `sym::Default`.
 +pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    if let hir::ExprKind::Path(ref qpath) = expr.kind {
 +        cx.qpath_res(qpath, expr.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
 +    match path {
 +        QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
 +        QPath::TypeRelative(_, s) => s.args,
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
 +    get_qpath_generics(path)
 +        .map_or([].as_ref(), |a| a.args)
 +        .iter()
 +        .filter_map(|a| {
 +            if let hir::GenericArg::Type(ty) = a {
 +                Some(ty)
 +            } else {
 +                None
 +            }
 +        })
 +}
 +
 +pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.get(0),
 +        QPath::TypeRelative(_, seg) => Some(seg),
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `QPath` against a slice of segment string literals.
 +///
 +/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
 +/// `rustc_hir::QPath`.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_qpath(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 +    match *path {
 +        QPath::Resolved(_, path) => match_path(path, segments),
 +        QPath::TypeRelative(ty, segment) => match ty.kind {
 +            TyKind::Path(ref inner_path) => {
 +                if let [prefix @ .., end] = segments {
 +                    if match_qpath(inner_path, prefix) {
 +                        return segment.ident.name.as_str() == *end;
 +                    }
 +                }
 +                false
 +            },
 +            _ => false,
 +        },
 +        QPath::LangItem(..) => false,
 +    }
 +}
 +
 +/// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
 +pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
 +    if let ExprKind::Path(p) = &expr.kind {
 +        cx.qpath_res(p, expr.hir_id)
 +    } else {
 +        Res::Err
 +    }
 +}
 +
 +/// Resolves the path to a `DefId` and checks if it matches the given path.
 +pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
 +    cx.qpath_res(path, hir_id)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 +///
 +/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
 +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
 +/// diagnostic item.
 +pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `Path` against a slice of segment string literals.
 +///
 +/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
 +/// `rustc_hir::Path`.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// if match_path(&trait_ref.path, &paths::HASH) {
 +///     // This is the `std::hash::Hash` trait.
 +/// }
 +///
 +/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
 +///     // This is a `rustc_middle::lint::Lint`.
 +/// }
 +/// ```
 +pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// If the expression is a path to a local, returns the canonical `HirId` of the local.
 +pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
 +    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
 +        if let Res::Local(id) = path.res {
 +            return Some(id);
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns true if the expression is a path to a local with the specified `HirId`.
 +/// Use this function to see if an expression matches a function argument or a match binding.
 +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
 +    path_to_local(expr) == Some(id)
 +}
 +
 +/// Gets the definition associated to a path.
-         ExprKind::Repeat(x, _) => is_default_equivalent(cx, x),
 +pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
 +    macro_rules! try_res {
 +        ($e:expr) => {
 +            match $e {
 +                Some(e) => e,
 +                None => return Res::Err,
 +            }
 +        };
 +    }
 +    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
 +        tcx.item_children(def_id)
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == name)
 +    }
 +
 +    let (krate, first, path) = match *path {
 +        [krate, first, ref path @ ..] => (krate, first, path),
 +        [primitive] => {
 +            return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
 +        },
 +        _ => return Res::Err,
 +    };
 +    let tcx = cx.tcx;
 +    let crates = tcx.crates(());
 +    let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
 +    let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
 +    let last = path
 +        .iter()
 +        .copied()
 +        // `get_def_path` seems to generate these empty segments for extern blocks.
 +        // We can just ignore them.
 +        .filter(|segment| !segment.is_empty())
 +        // for each segment, find the child item
 +        .try_fold(first, |item, segment| {
 +            let def_id = item.res.def_id();
 +            if let Some(item) = item_child_by_name(tcx, def_id, segment) {
 +                Some(item)
 +            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
 +                // it is not a child item so check inherent impl items
 +                tcx.inherent_impls(def_id)
 +                    .iter()
 +                    .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
 +            } else {
 +                None
 +            }
 +        });
 +    try_res!(last).res.expect_non_local()
 +}
 +
 +/// Convenience function to get the `DefId` of a trait by path.
 +/// It could be a trait or trait alias.
 +pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 +    match path_to_res(cx, path) {
 +        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
 +        _ => None,
 +    }
 +}
 +
 +/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 +///
 +/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
 +///
 +/// ```rust
 +/// struct Point(isize, isize);
 +///
 +/// impl std::ops::Add for Point {
 +///     type Output = Self;
 +///
 +///     fn add(self, other: Self) -> Self {
 +///         Point(0, 0)
 +///     }
 +/// }
 +/// ```
 +pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != hir::CRATE_HIR_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
 +        if let hir::ItemKind::Impl(impl_) = &item.kind;
 +        then { return impl_.of_trait.as_ref(); }
 +    }
 +    None
 +}
 +
 +/// This method will return tuple of projection stack and root of the expression,
 +/// used in `can_mut_borrow_both`.
 +///
 +/// For example, if `e` represents the `v[0].a.b[x]`
 +/// this method will return a tuple, composed of a `Vec`
 +/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
 +/// and an `Expr` for root of them, `v`
 +fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
 +    let mut result = vec![];
 +    let root = loop {
 +        match e.kind {
 +            ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
 +                result.push(e);
 +                e = ep;
 +            },
 +            _ => break e,
 +        };
 +    };
 +    result.reverse();
 +    (result, root)
 +}
 +
 +/// Checks if two expressions can be mutably borrowed simultaneously
 +/// and they aren't dependent on borrowing same thing twice
 +pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
 +    let (s1, r1) = projection_stack(e1);
 +    let (s2, r2) = projection_stack(e2);
 +    if !eq_expr_value(cx, r1, r2) {
 +        return true;
 +    }
 +    for (x1, x2) in s1.iter().zip(s2.iter()) {
 +        match (&x1.kind, &x2.kind) {
 +            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
 +                if i1 != i2 {
 +                    return true;
 +                }
 +            },
 +            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
 +                if !eq_expr_value(cx, i1, i2) {
 +                    return false;
 +                }
 +            },
 +            _ => return false,
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
 +/// constructor from the std library
 +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
 +    let std_types_symbols = &[
 +        sym::String,
 +        sym::Vec,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::HashMap,
 +        sym::BTreeMap,
 +        sym::HashSet,
 +        sym::BTreeSet,
 +        sym::BinaryHeap,
 +    ];
 +
 +    if let QPath::TypeRelative(_, method) = path {
 +        if method.ident.name == sym::new {
 +            if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +                if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +                    return std_types_symbols
 +                        .iter()
 +                        .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did));
 +                }
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
 +/// It doesn't cover all cases, for example indirect function calls (some of std
 +/// functions are supported) but it is the best we have.
 +pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    match &e.kind {
 +        ExprKind::Lit(lit) => match lit.node {
 +            LitKind::Bool(false) | LitKind::Int(0, _) => true,
 +            LitKind::Str(s, _) => s.is_empty(),
 +            _ => false,
 +        },
 +        ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
-         if let MatchSource::TryDesugar = *source {
++        ExprKind::Repeat(x, y) => if_chain! {
++            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
++            if let LitKind::Int(v, _) = const_lit.node;
++            if v <= 32 && is_default_equivalent(cx, x);
++            then {
++                true
++            }
++            else {
++                false
++            }
++        },
 +        ExprKind::Call(repl_func, _) => if_chain! {
 +            if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
 +            if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
 +            if is_diag_trait_item(cx, repl_def_id, sym::Default)
 +                || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
 +        ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
 +        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the top level expression can be moved into a closure as is.
 +/// Currently checks for:
 +/// * Break/Continue outside the given loop HIR ids.
 +/// * Yield/Return statments.
 +/// * Inline assembly.
 +/// * Usages of a field of a local where the type of the local can be partially moved.
 +///
 +/// For example, given the following function:
 +///
 +/// ```
 +/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
 +///     for item in iter {
 +///         let s = item.1;
 +///         if item.0 > 10 {
 +///             continue;
 +///         } else {
 +///             s.clear();
 +///         }
 +///     }
 +/// }
 +/// ```
 +///
 +/// When called on the expression `item.0` this will return false unless the local `item` is in the
 +/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
 +/// isn't always safe to move into a closure when only a single field is needed.
 +///
 +/// When called on the `continue` expression this will return false unless the outer loop expression
 +/// is in the `loop_ids` set.
 +///
 +/// Note that this check is not recursive, so passing the `if` expression will always return true
 +/// even though sub-expressions might return false.
 +pub fn can_move_expr_to_closure_no_visit(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    loop_ids: &[HirId],
 +    ignore_locals: &HirIdSet,
 +) -> bool {
 +    match expr.kind {
 +        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
 +        | ExprKind::Continue(Destination { target_id: Ok(id), .. })
 +            if loop_ids.contains(&id) =>
 +        {
 +            true
 +        },
 +        ExprKind::Break(..)
 +        | ExprKind::Continue(_)
 +        | ExprKind::Ret(_)
 +        | ExprKind::Yield(..)
 +        | ExprKind::InlineAsm(_)
 +        | ExprKind::LlvmInlineAsm(_) => false,
 +        // Accessing a field of a local value can only be done if the type isn't
 +        // partially moved.
 +        ExprKind::Field(
 +            &Expr {
 +                hir_id,
 +                kind:
 +                    ExprKind::Path(QPath::Resolved(
 +                        _,
 +                        Path {
 +                            res: Res::Local(local_id),
 +                            ..
 +                        },
 +                    )),
 +                ..
 +            },
 +            _,
 +        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
 +            // TODO: check if the local has been partially moved. Assume it has for now.
 +            false
 +        },
 +        _ => true,
 +    }
 +}
 +
 +/// How a local is captured by a closure
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum CaptureKind {
 +    Value,
 +    Ref(Mutability),
 +}
 +impl CaptureKind {
 +    pub fn is_imm_ref(self) -> bool {
 +        self == Self::Ref(Mutability::Not)
 +    }
 +}
 +impl std::ops::BitOr for CaptureKind {
 +    type Output = Self;
 +    fn bitor(self, rhs: Self) -> Self::Output {
 +        match (self, rhs) {
 +            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
 +            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
 +            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
 +            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
 +        }
 +    }
 +}
 +impl std::ops::BitOrAssign for CaptureKind {
 +    fn bitor_assign(&mut self, rhs: Self) {
 +        *self = *self | rhs;
 +    }
 +}
 +
 +/// Given an expression referencing a local, determines how it would be captured in a closure.
 +/// Note as this will walk up to parent expressions until the capture can be determined it should
 +/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
 +/// function argument (other than a receiver).
 +pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind {
 +    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
 +        let mut capture = CaptureKind::Ref(Mutability::Not);
 +        pat.each_binding_or_first(&mut |_, id, span, _| match cx
 +            .typeck_results()
 +            .extract_binding_mode(cx.sess(), id, span)
 +            .unwrap()
 +        {
 +            BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
 +                capture = CaptureKind::Value;
 +            },
 +            BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
 +                capture = CaptureKind::Ref(Mutability::Mut);
 +            },
 +            _ => (),
 +        });
 +        capture
 +    }
 +
 +    debug_assert!(matches!(
 +        e.kind,
 +        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
 +    ));
 +
 +    let mut child_id = e.hir_id;
 +    let mut capture = CaptureKind::Value;
 +    let mut capture_expr_ty = e;
 +
 +    for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
 +        if let [Adjustment {
 +            kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
 +            target,
 +        }, ref adjust @ ..] = *cx
 +            .typeck_results()
 +            .adjustments()
 +            .get(child_id)
 +            .map_or(&[][..], |x| &**x)
 +        {
 +            if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
 +                *adjust.last().map_or(target, |a| a.target).kind()
 +            {
 +                return CaptureKind::Ref(mutability);
 +            }
 +        }
 +
 +        match parent {
 +            Node::Expr(e) => match e.kind {
 +                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
 +                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
 +                ExprKind::Assign(lhs, ..) | ExprKind::Assign(_, lhs, _) if lhs.hir_id == child_id => {
 +                    return CaptureKind::Ref(Mutability::Mut);
 +                },
 +                ExprKind::Field(..) => {
 +                    if capture == CaptureKind::Value {
 +                        capture_expr_ty = e;
 +                    }
 +                },
 +                ExprKind::Let(pat, ..) => {
 +                    let mutability = match pat_capture_kind(cx, pat) {
 +                        CaptureKind::Value => Mutability::Not,
 +                        CaptureKind::Ref(m) => m,
 +                    };
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                ExprKind::Match(_, arms, _) => {
 +                    let mut mutability = Mutability::Not;
 +                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
 +                        match capture {
 +                            CaptureKind::Value => break,
 +                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
 +                            CaptureKind::Ref(Mutability::Not) => (),
 +                        }
 +                    }
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                _ => break,
 +            },
 +            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
 +                CaptureKind::Value => break,
 +                capture @ CaptureKind::Ref(_) => return capture,
 +            },
 +            _ => break,
 +        }
 +
 +        child_id = parent_id;
 +    }
 +
 +    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
 +        // Copy types are never automatically captured by value.
 +        CaptureKind::Ref(Mutability::Not)
 +    } else {
 +        capture
 +    }
 +}
 +
 +/// Checks if the expression can be moved into a closure as is. This will return a list of captures
 +/// if so, otherwise, `None`.
 +pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
 +    struct V<'cx, 'tcx> {
 +        cx: &'cx LateContext<'tcx>,
 +        // Stack of potential break targets contained in the expression.
 +        loops: Vec<HirId>,
 +        /// Local variables created in the expression. These don't need to be captured.
 +        locals: HirIdSet,
 +        /// Whether this expression can be turned into a closure.
 +        allow_closure: bool,
 +        /// Locals which need to be captured, and whether they need to be by value, reference, or
 +        /// mutable reference.
 +        captures: HirIdMap<CaptureKind>,
 +    }
 +    impl Visitor<'tcx> for V<'_, 'tcx> {
 +        type Map = ErasedMap<'tcx>;
 +        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +            NestedVisitorMap::None
 +        }
 +
 +        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +            if !self.allow_closure {
 +                return;
 +            }
 +
 +            match e.kind {
 +                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
 +                    if !self.locals.contains(&l) {
 +                        let cap = capture_local_usage(self.cx, e);
 +                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
 +                    }
 +                },
 +                ExprKind::Closure(..) => {
 +                    let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id).to_def_id();
 +                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
 +                        let local_id = match capture.place.base {
 +                            PlaceBase::Local(id) => id,
 +                            PlaceBase::Upvar(var) => var.var_path.hir_id,
 +                            _ => continue,
 +                        };
 +                        if !self.locals.contains(&local_id) {
 +                            let capture = match capture.info.capture_kind {
 +                                UpvarCapture::ByValue(_) => CaptureKind::Value,
 +                                UpvarCapture::ByRef(borrow) => match borrow.kind {
 +                                    BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
 +                                    BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
 +                                        CaptureKind::Ref(Mutability::Mut)
 +                                    },
 +                                },
 +                            };
 +                            self.captures
 +                                .entry(local_id)
 +                                .and_modify(|e| *e |= capture)
 +                                .or_insert(capture);
 +                        }
 +                    }
 +                },
 +                ExprKind::Loop(b, ..) => {
 +                    self.loops.push(e.hir_id);
 +                    self.visit_block(b);
 +                    self.loops.pop();
 +                },
 +                _ => {
 +                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
 +                    walk_expr(self, e);
 +                },
 +            }
 +        }
 +
 +        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
 +            p.each_binding_or_first(&mut |_, id, _, _| {
 +                self.locals.insert(id);
 +            });
 +        }
 +    }
 +
 +    let mut v = V {
 +        cx,
 +        allow_closure: true,
 +        loops: Vec::new(),
 +        locals: HirIdSet::default(),
 +        captures: HirIdMap::default(),
 +    };
 +    v.visit_expr(expr);
 +    v.allow_closure.then(|| v.captures)
 +}
 +
 +/// Returns the method names and argument list of nested method call expressions that make up
 +/// `expr`. method/span lists are sorted with the most recent call first.
 +pub fn method_calls<'tcx>(
 +    expr: &'tcx Expr<'tcx>,
 +    max_depth: usize,
 +) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
 +    let mut method_names = Vec::with_capacity(max_depth);
 +    let mut arg_lists = Vec::with_capacity(max_depth);
 +    let mut spans = Vec::with_capacity(max_depth);
 +
 +    let mut current = expr;
 +    for _ in 0..max_depth {
 +        if let ExprKind::MethodCall(path, span, args, _) = &current.kind {
 +            if args.iter().any(|e| e.span.from_expansion()) {
 +                break;
 +            }
 +            method_names.push(path.ident.name);
 +            arg_lists.push(&**args);
 +            spans.push(*span);
 +            current = &args[0];
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    (method_names, arg_lists, spans)
 +}
 +
 +/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 +///
 +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
 +/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 +/// containing the `Expr`s for
 +/// `.bar()` and `.baz()`
 +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
 +    let mut current = expr;
 +    let mut matched = Vec::with_capacity(methods.len());
 +    for method_name in methods.iter().rev() {
 +        // method chains are stored last -> first
 +        if let ExprKind::MethodCall(path, _, args, _) = current.kind {
 +            if path.ident.name.as_str() == *method_name {
 +                if args.iter().any(|e| e.span.from_expansion()) {
 +                    return None;
 +                }
 +                matched.push(args); // build up `matched` backwards
 +                current = &args[0]; // go to parent expression
 +            } else {
 +                return None;
 +            }
 +        } else {
 +            return None;
 +        }
 +    }
 +    // Reverse `matched` so that it is in the same order as `methods`.
 +    matched.reverse();
 +    Some(matched)
 +}
 +
 +/// Returns `true` if the provided `def_id` is an entrypoint to a program.
 +pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    cx.tcx
 +        .entry_fn(())
 +        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 +}
 +
 +/// Returns `true` if the expression is in the program's `#[panic_handler]`.
 +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    let parent = cx.tcx.hir().get_parent_item(e.hir_id);
 +    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
 +    Some(def_id) == cx.tcx.lang_items().panic_impl()
 +}
 +
 +/// Gets the name of the item the expression is in, if available.
 +pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
 +    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
 +    match cx.tcx.hir().find(parent_id) {
 +        Some(
 +            Node::Item(Item { ident, .. })
 +            | Node::TraitItem(TraitItem { ident, .. })
 +            | Node::ImplItem(ImplItem { ident, .. }),
 +        ) => Some(ident.name),
 +        _ => None,
 +    }
 +}
 +
 +pub struct ContainsName {
 +    pub name: Symbol,
 +    pub result: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ContainsName {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_name(&mut self, _: Span, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Checks if an `Expr` contains a certain name.
 +pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
 +    let mut cn = ContainsName { name, result: false };
 +    cn.visit_expr(expr);
 +    cn.result
 +}
 +
 +/// Returns `true` if `expr` contains a return expression
 +pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    struct RetCallFinder {
 +        found: bool,
 +    }
 +
 +    impl<'tcx> hir::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 {
 +                hir::intravisit::walk_expr(self, expr);
 +            }
 +        }
 +
 +        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
 +            hir::intravisit::NestedVisitorMap::None
 +        }
 +    }
 +
 +    let mut visitor = RetCallFinder { found: false };
 +    visitor.visit_expr(expr);
 +    visitor.found
 +}
 +
 +struct FindMacroCalls<'a, 'b> {
 +    names: &'a [&'b str],
 +    result: Vec<Span>,
 +}
 +
 +impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
 +            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
 +    }
 +}
 +
 +/// Finds calls of the specified macros in a function body.
 +pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
 +    let mut fmc = FindMacroCalls {
 +        names,
 +        result: Vec::new(),
 +    };
 +    fmc.visit_expr(&body.value);
 +    fmc.result
 +}
 +
 +/// 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.with_lo(line_start)
 +}
 +
 +/// Gets the parent node, if any.
 +pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
 +    tcx.hir().parent_iter(id).next().map(|(_, node)| node)
 +}
 +
 +/// Gets the parent expression, if any –- this is useful to constrain a lint.
 +pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    get_parent_expr_for_hir(cx, e.hir_id)
 +}
 +
 +/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
 +/// constraint lints
 +pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
 +    match get_parent_node(cx.tcx, hir_id) {
 +        Some(Node::Expr(parent)) => Some(parent),
 +        _ => None,
 +    }
 +}
 +
 +pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
 +    let map = &cx.tcx.hir();
 +    let enclosing_node = map
 +        .get_enclosing_scope(hir_id)
 +        .and_then(|enclosing_id| map.find(enclosing_id));
 +    enclosing_node.and_then(|node| match node {
 +        Node::Block(block) => Some(block),
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(_, _, eid),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(_, eid),
 +            ..
 +        }) => match cx.tcx.hir().body(eid).value.kind {
 +            ExprKind::Block(block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Gets the loop or closure enclosing the given expression, if any.
 +pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
 +        match node {
 +            Node::Expr(
 +                e
 +                @
 +                Expr {
 +                    kind: ExprKind::Loop(..) | ExprKind::Closure(..),
 +                    ..
 +                },
 +            ) => return Some(e),
 +            Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
 +            _ => break,
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets the parent node if it's an impl block.
 +pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
 +    match tcx.hir().parent_iter(id).next() {
 +        Some((
 +            _,
 +            Node::Item(Item {
 +                kind: ItemKind::Impl(imp),
 +                ..
 +            }),
 +        )) => Some(imp),
 +        _ => None,
 +    }
 +}
 +
 +/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
 +pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    let mut iter = tcx.hir().parent_iter(expr.hir_id);
 +    match iter.next() {
 +        Some((
 +            _,
 +            Node::Expr(Expr {
 +                kind: ExprKind::If(_, _, Some(else_expr)),
 +                ..
 +            }),
 +        )) => else_expr.hir_id == expr.hir_id,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks whether the given expression is a constant integer of the given value.
 +/// unlike `is_integer_literal`, this version does const folding
 +pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
 +    if is_integer_literal(e, value) {
 +        return true;
 +    }
 +    let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
 +    if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
 +        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)
 +}
 +
 +/// Checks if an expression is constructing a tuple-like enum variant or struct
 +pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(fun, _) = expr.kind {
 +        if let ExprKind::Path(ref qp) = fun.kind {
 +            let res = cx.qpath_res(qp, fun.hir_id);
 +            return match res {
 +                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
 +                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
 +                _ => false,
 +            };
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if a pattern is refutable.
 +// TODO: should be implemented using rustc/mir_build/thir machinery
 +pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 +    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
 +        matches!(
 +            cx.qpath_res(qpath, id),
 +            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
 +        )
 +    }
 +
 +    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
 +        i.into_iter().any(|pat| is_refutable(cx, pat))
 +    }
 +
 +    match pat.kind {
 +        PatKind::Wild => false,
 +        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
 +        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
 +        PatKind::Lit(..) | PatKind::Range(..) => true,
 +        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
 +        PatKind::Or(pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats)
 +        },
 +        PatKind::Tuple(pats, _) => are_refutable(cx, pats),
 +        PatKind::Struct(ref qpath, fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
 +        PatKind::Slice(head, middle, tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind() {
 +                rustc_ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
 +/// the function once on the given pattern.
 +pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
 +    if let PatKind::Or(pats) = pat.kind {
 +        pats.iter().for_each(f);
 +    } else {
 +        f(pat);
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    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(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(QPath::Resolved(None, path)) = slf.kind;
 +        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>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
 +            if is_lang_ctor(cx, path, ResultOk);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if path_to_local_id(arm.body, hir_id);
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            is_lang_ctor(cx, path, ResultErr)
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
++        if *source == MatchSource::TryDesugar {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) ||
 +                (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
 +            then {
 +                return Some(expr);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Returns `true` if the lint is allowed in the current context
 +///
 +/// Useful for skipping long running code when it's unnecessary
 +pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
 +    while let PatKind::Ref(subpat, _) = pat.kind {
 +        pat = subpat;
 +    }
 +    pat
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
 +    Integer::from_int_ty(&tcx, ity).size().bits()
 +}
 +
 +#[allow(clippy::cast_possible_wrap)]
 +/// Turn a constant int byte representation into an i128
 +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as i128) << amt) >> amt
 +}
 +
 +#[allow(clippy::cast_sign_loss)]
 +/// clip unused bytes
 +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as u128) << amt) >> amt
 +}
 +
 +/// clip unused bytes
 +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
 +    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +pub fn 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
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
 +/// ```
 +pub fn match_function_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    path: &[&str],
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        if match_def_path(cx, fun_def_id, path);
 +        then {
 +            return Some(args)
 +        }
 +    };
 +    None
 +}
 +
 +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 +/// any.
 +///
 +/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items.
 +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
 +    let search_path = cx.get_def_path(did);
 +    paths
 +        .iter()
 +        .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
 +}
 +
 +/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of
 +/// matching path, if any.
 +pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option<usize> {
 +    diag_items
 +        .iter()
 +        .position(|item| cx.tcx.is_diagnostic_item(*item, def_id))
 +}
 +
 +/// Checks if the given `DefId` matches the path.
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
 +    // We should probably move to Symbols in Clippy as well rather than interning every time.
 +    let path = cx.get_def_path(did);
 +    syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
 +}
 +
 +pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(func, [arg]) = expr.kind {
 +        expr_path_res(cx, func)
 +            .opt_def_id()
 +            .map_or(false, |id| match_panic_def_id(cx, id))
 +            .then(|| arg)
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
 +    match_any_def_paths(
 +        cx,
 +        did,
 +        &[
 +            &paths::BEGIN_PANIC,
 +            &paths::BEGIN_PANIC_FMT,
 +            &paths::PANIC_ANY,
 +            &paths::PANICKING_PANIC,
 +            &paths::PANICKING_PANIC_FMT,
 +            &paths::PANICKING_PANIC_STR,
 +        ],
 +    )
 +    .is_some()
 +}
 +
 +/// Returns the list of condition expressions and the list of blocks in a
 +/// sequence of `if/else`.
 +/// E.g., this returns `([a, b], [c, d, e])` for the expression
 +/// `if a { c } else if b { d } else { e }`.
 +pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
 +    let mut conds = Vec::new();
 +    let mut blocks: Vec<&Block<'_>> = Vec::new();
 +
 +    while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
 +        conds.push(&*cond);
 +        if let ExprKind::Block(block, _) = then.kind {
 +            blocks.push(block);
 +        } else {
 +            panic!("ExprKind::If node is not an ExprKind::Block");
 +        }
 +
 +        if let Some(else_expr) = r#else {
 +            expr = else_expr;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    // final `else {..}`
 +    if !blocks.is_empty() {
 +        if let ExprKind::Block(block, _) = expr.kind {
 +            blocks.push(block);
 +        }
 +    }
 +
 +    (conds, blocks)
 +}
 +
 +/// Checks if the given function kind is an async function.
 +pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 +    matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
 +}
 +
 +/// Peels away all the compiler generated code surrounding the body of an async function,
 +pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(
 +        _,
 +        &[Expr {
 +            kind: ExprKind::Closure(_, _, body, _, _),
 +            ..
 +        }],
 +    ) = body.value.kind
 +    {
 +        if let ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr:
 +                    Some(Expr {
 +                        kind: ExprKind::DropTemps(expr),
 +                        ..
 +                    }),
 +                ..
 +            },
 +            _,
 +        ) = tcx.hir().body(body).value.kind
 +        {
 +            return Some(expr);
 +        }
 +    };
 +    None
 +}
 +
 +// Finds the `#[must_use]` attribute, if any
 +pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 +    attrs.iter().find(|a| a.has_name(sym::must_use))
 +}
 +
 +// check if expr is calling method or function with #[must_use] attribute
 +pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let did = match expr.kind {
 +        ExprKind::Call(path, _) => if_chain! {
 +            if let ExprKind::Path(ref qpath) = path.kind;
 +            if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
 +            then {
 +                Some(did)
 +            } else {
 +                None
 +            }
 +        },
 +        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        _ => None,
 +    };
 +
 +    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 +}
 +
 +/// Checks if an expression represents the identity function
 +/// Only examines closures and `std::convert::identity`
 +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
 +    /// * `|x| x`
 +    /// * `|x| return x`
 +    /// * `|x| { return x }`
 +    /// * `|x| { return x; }`
 +    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 +        let id = if_chain! {
 +            if let [param] = func.params;
 +            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
 +            then {
 +                id
 +            } else {
 +                return false;
 +            }
 +        };
 +
 +        let mut expr = &func.value;
 +        loop {
 +            match expr.kind {
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
 +                | ExprKind::Ret(Some(e)) => expr = e,
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
 +                    if_chain! {
 +                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
 +                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
 +                        then {
 +                            expr = ret_val;
 +                        } else {
 +                            return false;
 +                        }
 +                    }
 +                },
 +                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
 +            }
 +        }
 +    }
 +
 +    match expr.kind {
 +        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
 +        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
 +        _ => false,
 +    }
 +}
 +
 +/// Gets the node where an expression is either used, or it's type is unified with another branch.
 +pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
 +    let mut child_id = expr.hir_id;
 +    let mut iter = tcx.hir().parent_iter(child_id);
 +    loop {
 +        match iter.next() {
 +            None => break None,
 +            Some((id, Node::Block(_))) => child_id = id,
 +            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
 +            Some((_, Node::Expr(expr))) => match expr.kind {
 +                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
 +                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
 +                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
 +                _ => break Some(Node::Expr(expr)),
 +            },
 +            Some((_, node)) => break Some(node),
 +        }
 +    }
 +}
 +
 +/// Checks if the result of an expression is used, or it's type is unified with another branch.
 +pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    !matches!(
 +        get_expr_use_or_unification_node(tcx, expr),
 +        None | Some(Node::Stmt(Stmt {
 +            kind: StmtKind::Expr(_)
 +                | StmtKind::Semi(_)
 +                | StmtKind::Local(Local {
 +                    pat: Pat {
 +                        kind: PatKind::Wild,
 +                        ..
 +                    },
 +                    ..
 +                }),
 +            ..
 +        }))
 +    )
 +}
 +
 +/// Checks if the expression is the final expression returned from a block.
 +pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
 +}
 +
 +pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr.path == sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// 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(hir::Impl { of_trait: Some(_), .. }))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates = cx
 +        .tcx
 +        .predicates_of(did)
 +        .predicates
 +        .iter()
 +        .filter_map(|(p, _)| if p.is_global(cx.tcx) { Some(*p) } else { None });
 +    traits::impossible_predicates(
 +        cx.tcx,
 +        traits::elaborate_predicates(cx.tcx, predicates)
 +            .map(|o| o.predicate)
 +            .collect::<Vec<_>>(),
 +    )
 +}
 +
 +/// Returns the `DefId` of the callee if the given expression is a function or method call.
 +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 +    match &expr.kind {
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(qpath),
 +                hir_id: path_hir_id,
 +                ..
 +            },
 +            ..,
 +        ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
 +        _ => None,
 +    }
 +}
 +
 +/// Returns Option<String> where String is a textual representation of the type encapsulated in the
 +/// slice iff the given expression is a slice of primitives (as defined in the
 +/// `is_recursively_primitive_type` function) and None otherwise.
 +pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
 +    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
 +    let expr_kind = expr_type.kind();
 +    let is_primitive = match expr_kind {
 +        rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type),
 +        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
 +            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
 +                is_recursively_primitive_type(element_type)
 +            } else {
 +                unreachable!()
 +            }
 +        },
 +        _ => false,
 +    };
 +
 +    if is_primitive {
 +        // if we have wrappers like Array, Slice or Tuple, print these
 +        // and get the type enclosed in the slice ref
 +        match expr_type.peel_refs().walk(cx.tcx).nth(1).unwrap().expect_ty().kind() {
 +            rustc_ty::Slice(..) => return Some("slice".into()),
 +            rustc_ty::Array(..) => return Some("array".into()),
 +            rustc_ty::Tuple(..) => return Some("tuple".into()),
 +            _ => {
 +                // is_recursively_primitive_type() should have taken care
 +                // of the rest and we can rely on the type that is found
 +                let refs_peeled = expr_type.peel_refs();
 +                return Some(refs_peeled.walk(cx.tcx).last().unwrap().to_string());
 +            },
 +        }
 +    }
 +    None
 +}
 +
 +/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
 +/// `hash` must be comformed with `eq`
 +pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 +where
 +    Hash: Fn(&T) -> u64,
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    match exprs {
 +        [a, b] if eq(a, b) => return vec![(a, b)],
 +        _ if exprs.len() <= 2 => return vec![],
 +        _ => {},
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: UnhashMap<u64, Vec<&_>> =
 +        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 +
 +    for expr in exprs {
 +        match map.entry(hash(expr)) {
 +            Entry::Occupied(mut o) => {
 +                for o in o.get() {
 +                    if eq(o, expr) {
 +                        match_expr_list.push((o, expr));
 +                    }
 +                }
 +                o.get_mut().push(expr);
 +            },
 +            Entry::Vacant(v) => {
 +                v.insert(vec![expr]);
 +            },
 +        }
 +    }
 +
 +    match_expr_list
 +}
 +
 +/// Peels off all references on the pattern. Returns the underlying pattern and the number of
 +/// references removed.
 +pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
 +        if let PatKind::Ref(pat, _) = pat.kind {
 +            peel(pat, count + 1)
 +        } else {
 +            (pat, count)
 +        }
 +    }
 +    peel(pat, 0)
 +}
 +
 +/// Peels of expressions while the given closure returns `Some`.
 +pub fn peel_hir_expr_while<'tcx>(
 +    mut expr: &'tcx Expr<'tcx>,
 +    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
 +) -> &'tcx Expr<'tcx> {
 +    while let Some(e) = f(expr) {
 +        expr = e;
 +    }
 +    expr
 +}
 +
 +/// Peels off up to the given number of references on the expression. Returns the underlying
 +/// expression and the number of references removed.
 +pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
 +    let mut remaining = count;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
 +            remaining -= 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count - remaining)
 +}
 +
 +/// Peels off all references on the expression. Returns the underlying expression and the number of
 +/// references removed.
 +pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
 +    let mut count = 0;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
 +            count += 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count)
 +}
 +
 +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 +pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 +    loop {
 +        match expr.kind {
 +            ExprKind::AddrOf(_, _, e) => expr = e,
 +            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +#[macro_export]
 +macro_rules! unwrap_cargo_metadata {
 +    ($cx: ident, $lint: ident, $deps: expr) => {{
 +        let mut command = cargo_metadata::MetadataCommand::new();
 +        if !$deps {
 +            command.no_deps();
 +        }
 +
 +        match command.exec() {
 +            Ok(metadata) => metadata,
 +            Err(err) => {
 +                span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
 +                return;
 +            },
 +        }
 +    }};
 +}
 +
 +pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if_chain! {
 +        if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
 +        if let Res::Def(_, def_id) = path.res;
 +        then {
 +            cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Checks whether item either has `test` attribute applied, or
 +/// is a module with `test` in its name.
 +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
 +    if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) {
 +        if tcx.has_attr(def_id.to_def_id(), sym::test) {
 +            return true;
 +        }
 +    }
 +
 +    matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
 +}
 +
 +macro_rules! op_utils {
 +    ($($name:ident $assign:ident)*) => {
 +        /// Binary operation traits like `LangItem::Add`
 +        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
 +
 +        /// Operator-Assign traits like `LangItem::AddAssign`
 +        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
 +
 +        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
 +        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
 +            match kind {
 +                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
 +                _ => None,
 +            }
 +        }
 +    };
 +}
 +
 +op_utils! {
 +    Add    AddAssign
 +    Sub    SubAssign
 +    Mul    MulAssign
 +    Div    DivAssign
 +    Rem    RemAssign
 +    BitXor BitXorAssign
 +    BitAnd BitAndAssign
 +    BitOr  BitOrAssign
 +    Shl    ShlAssign
 +    Shr    ShrAssign
 +}
index 4a28c7dd9a04a3885251ef7ab44e7d5ea65aa7fe,0000000000000000000000000000000000000000..68dd1b29845a570cc4f6b30af834414fc34d70c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,232 -1,0 +1,241 @@@
-         let (prefix, mut sans_prefix) = if let Radix::Decimal = radix {
 +use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind};
 +use std::iter;
 +
 +#[derive(Debug, PartialEq, Copy, Clone)]
 +pub enum Radix {
 +    Binary,
 +    Octal,
 +    Decimal,
 +    Hexadecimal,
 +}
 +
 +impl Radix {
 +    /// Returns a reasonable digit group size for this radix.
 +    #[must_use]
 +    fn suggest_grouping(self) -> usize {
 +        match self {
 +            Self::Binary | Self::Hexadecimal => 4,
 +            Self::Octal | Self::Decimal => 3,
 +        }
 +    }
 +}
 +
 +/// A helper method to format numeric literals with digit grouping.
 +/// `lit` must be a valid numeric literal without suffix.
 +pub fn format(lit: &str, type_suffix: Option<&str>, float: bool) -> String {
 +    NumericLiteral::new(lit, type_suffix, float).format()
 +}
 +
 +#[derive(Debug)]
 +pub struct NumericLiteral<'a> {
 +    /// Which radix the literal was represented in.
 +    pub radix: Radix,
 +    /// The radix prefix, if present.
 +    pub prefix: Option<&'a str>,
 +
 +    /// The integer part of the number.
 +    pub integer: &'a str,
 +    /// The fraction part of the number.
 +    pub fraction: Option<&'a str>,
 +    /// The exponent separator (b'e' or b'E') including preceding underscore if present
 +    /// and the exponent part.
 +    pub exponent: Option<(&'a str, &'a str)>,
 +
 +    /// The type suffix, including preceding underscore if present.
 +    pub suffix: Option<&'a str>,
 +}
 +
 +impl<'a> NumericLiteral<'a> {
 +    pub fn from_lit(src: &'a str, lit: &Lit) -> Option<NumericLiteral<'a>> {
 +        NumericLiteral::from_lit_kind(src, &lit.kind)
 +    }
 +
 +    pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
 +        if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
 +            let (unsuffixed, suffix) = split_suffix(src, lit_kind);
 +            let float = matches!(lit_kind, LitKind::Float(..));
 +            Some(NumericLiteral::new(unsuffixed, suffix, float))
 +        } else {
 +            None
 +        }
 +    }
 +
 +    #[must_use]
 +    pub fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self {
 +        // Determine delimiter for radix prefix, if present, and radix.
 +        let radix = if lit.starts_with("0x") {
 +            Radix::Hexadecimal
 +        } else if lit.starts_with("0b") {
 +            Radix::Binary
 +        } else if lit.starts_with("0o") {
 +            Radix::Octal
 +        } else {
 +            Radix::Decimal
 +        };
 +
 +        // Grab part of the literal after prefix, if present.
-             output.push_str(separator);
-             Self::group_digits(&mut output, exponent, group_size, true, false);
++        let (prefix, mut sans_prefix) = if radix == Radix::Decimal {
 +            (None, lit)
 +        } else {
 +            let (p, s) = lit.split_at(2);
 +            (Some(p), s)
 +        };
 +
 +        if suffix.is_some() && sans_prefix.ends_with('_') {
 +            // The '_' before the suffix isn't part of the digits
 +            sans_prefix = &sans_prefix[..sans_prefix.len() - 1];
 +        }
 +
 +        let (integer, fraction, exponent) = Self::split_digit_parts(sans_prefix, float);
 +
 +        Self {
 +            radix,
 +            prefix,
 +            integer,
 +            fraction,
 +            exponent,
 +            suffix,
 +        }
 +    }
 +
 +    pub fn is_decimal(&self) -> bool {
 +        self.radix == Radix::Decimal
 +    }
 +
 +    pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(&str, &str)>) {
 +        let mut integer = digits;
 +        let mut fraction = None;
 +        let mut exponent = None;
 +
 +        if float {
 +            for (i, c) in digits.char_indices() {
 +                match c {
 +                    '.' => {
 +                        integer = &digits[..i];
 +                        fraction = Some(&digits[i + 1..]);
 +                    },
 +                    'e' | 'E' => {
 +                        let exp_start = if digits[..i].ends_with('_') { i - 1 } else { i };
 +
 +                        if integer.len() > exp_start {
 +                            integer = &digits[..exp_start];
 +                        } else {
 +                            fraction = Some(&digits[integer.len() + 1..exp_start]);
 +                        };
 +                        exponent = Some((&digits[exp_start..=i], &digits[i + 1..]));
 +                        break;
 +                    },
 +                    _ => {},
 +                }
 +            }
 +        }
 +
 +        (integer, fraction, exponent)
 +    }
 +
 +    /// Returns literal formatted in a sensible way.
 +    pub fn format(&self) -> String {
 +        let mut output = String::new();
 +
 +        if let Some(prefix) = self.prefix {
 +            output.push_str(prefix);
 +        }
 +
 +        let group_size = self.radix.suggest_grouping();
 +
 +        Self::group_digits(
 +            &mut output,
 +            self.integer,
 +            group_size,
 +            true,
 +            self.radix == Radix::Hexadecimal,
 +        );
 +
 +        if let Some(fraction) = self.fraction {
 +            output.push('.');
 +            Self::group_digits(&mut output, fraction, group_size, false, false);
 +        }
 +
 +        if let Some((separator, exponent)) = self.exponent {
++            if exponent != "0" {
++                output.push_str(separator);
++                Self::group_digits(&mut output, exponent, group_size, true, false);
++            }
 +        }
 +
 +        if let Some(suffix) = self.suffix {
 +            if output.ends_with('.') {
 +                output.push('0');
 +            }
 +            output.push('_');
 +            output.push_str(suffix);
 +        }
 +
 +        output
 +    }
 +
 +    pub fn group_digits(output: &mut String, input: &str, group_size: usize, partial_group_first: bool, pad: bool) {
 +        debug_assert!(group_size > 0);
 +
 +        let mut digits = input.chars().filter(|&c| c != '_');
 +
++        // The exponent may have a sign, output it early, otherwise it will be
++        // treated as a digit
++        if digits.clone().next() == Some('-') {
++            let _ = digits.next();
++            output.push('-');
++        }
++
 +        let first_group_size;
 +
 +        if partial_group_first {
 +            first_group_size = (digits.clone().count() - 1) % group_size + 1;
 +            if pad {
 +                for _ in 0..group_size - first_group_size {
 +                    output.push('0');
 +                }
 +            }
 +        } else {
 +            first_group_size = group_size;
 +        }
 +
 +        for _ in 0..first_group_size {
 +            if let Some(digit) = digits.next() {
 +                output.push(digit);
 +            }
 +        }
 +
 +        for (c, i) in iter::zip(digits, (0..group_size).cycle()) {
 +            if i == 0 {
 +                output.push('_');
 +            }
 +            output.push(c);
 +        }
 +    }
 +}
 +
 +fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
 +    debug_assert!(lit_kind.is_numeric());
 +    lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
 +        let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
 +        (unsuffixed, Some(suffix))
 +    })
 +}
 +
 +fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
 +    debug_assert!(lit_kind.is_numeric());
 +    let suffix = match lit_kind {
 +        LitKind::Int(_, int_lit_kind) => match int_lit_kind {
 +            LitIntType::Signed(int_ty) => Some(int_ty.name_str()),
 +            LitIntType::Unsigned(uint_ty) => Some(uint_ty.name_str()),
 +            LitIntType::Unsuffixed => None,
 +        },
 +        LitKind::Float(_, float_lit_kind) => match float_lit_kind {
 +            LitFloatType::Suffixed(float_ty) => Some(float_ty.name_str()),
 +            LitFloatType::Unsuffixed => None,
 +        },
 +        _ => None,
 +    };
 +
 +    suffix.map(str::len)
 +}
index 5e0182ec1b8ead12d356448c3675a8fa190fb8b4,0000000000000000000000000000000000000000..e43c5756021452e30e5f0fdb5706858a5c7237c8
mode 100644,000000..100644
--- /dev/null
@@@ -1,181 -1,0 +1,187 @@@
 +//! 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] = ["core", "any", "Any"];
 +#[cfg(feature = "metadata-collector-lint")]
 +pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
 +#[cfg(feature = "metadata-collector-lint")]
 +pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
 +    ["rustc_lint_defs", "Applicability", "Unspecified"],
 +    ["rustc_lint_defs", "Applicability", "HasPlaceholders"],
 +    ["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
 +    ["rustc_lint_defs", "Applicability", "MachineApplicable"],
 +];
 +#[cfg(feature = "metadata-collector-lint")]
 +pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
 +pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
 +pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
 +pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
 +pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
 +pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
 +/// Preferably use the diagnostic item `sym::Borrow` where possible
 +pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
 +pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
 +pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
 +pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 +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_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
 +pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
 +pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
 +/// Preferably use the diagnostic item `sym::deref_method` where possible
 +pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
 +pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
 +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 DURATION: [&str; 3] = ["core", "time", "Duration"];
 +#[cfg(feature = "internal-lints")]
 +pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
 +pub const EXIT: [&str; 3] = ["std", "process", "exit"];
 +pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
 +pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
 +pub const FILE: [&str; 3] = ["std", "fs", "File"];
 +pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
 +pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 +pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
 +pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 +pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
 +pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 +pub const HASH: [&str; 3] = ["core", "hash", "Hash"];
 +pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
 +pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 +pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
 +#[cfg(feature = "internal-lints")]
 +pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 +#[cfg(feature = "internal-lints")]
 +pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 +pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
 +pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
 +pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 +pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
 +pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
 +pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
 +pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
 +pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
 +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 +#[cfg(feature = "internal-lints")]
 +pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
 +#[cfg(feature = "internal-lints")]
 +pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
 +pub const LIBC_STRLEN: [&str; 2] = ["libc", "strlen"];
 +#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
 +pub const LINT: [&str; 2] = ["rustc_lint_defs", "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 MEM_SIZE_OF: [&str; 3] = ["core", "mem", "size_of"];
 +pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"];
 +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"];
 +/// Preferably use the diagnostic item `sym::Option` where possible
 +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_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(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"];
 +pub(super) const PANICKING_PANIC_FMT: [&str; 3] = ["core", "panicking", "panic_fmt"];
 +pub(super) const PANICKING_PANIC_STR: [&str; 3] = ["core", "panicking", "panic_str"];
 +pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
 +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_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 PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
 +pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
 +pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 +pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 +pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
 +pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
 +pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 +pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 +pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"];
 +pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"];
 +pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"];
 +pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"];
 +pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"];
 +pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"];
 +pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
 +pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
 +pub const PTR_WRITE: [&str; 3] = ["core", "ptr", "write"];
 +pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
 +pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"];
 +pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"];
 +pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 +pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 +pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 +pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 +pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
++#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
 +/// Preferably use the diagnostic item `sym::Result` where possible
 +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; 3] = ["serde", "de", "Deserialize"];
 +pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 +pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
 +pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
 +pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 +pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 +pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 +pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 +pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"];
 +pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
 +pub const 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 STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
 +pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
 +pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
 +pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 +#[cfg(feature = "internal-lints")]
 +pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 +pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 +pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 +pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
 +pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 +pub const VEC_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 ab05a0b423853f245ca00b5d2f940383da0d8ef9,0000000000000000000000000000000000000000..5b0efb1fd7132811c449eb408729f4ea08f40870
mode 100644,000000..100644
--- /dev/null
@@@ -1,746 -1,0 +1,746 @@@
-     if let Some('(') = chars.next() {
 +//! Contains utility functions to generate suggestions.
 +#![deny(clippy::missing_docs_in_private_items)]
 +
 +use crate::higher;
 +use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
 +use rustc_ast::util::parser::AssocOp;
 +use rustc_ast::{ast, token};
 +use rustc_ast_pretty::pprust::token_kind_to_string;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::{EarlyContext, LateContext, LintContext};
 +use rustc_span::source_map::{CharPos, Span};
 +use rustc_span::{BytePos, Pos, SyntaxContext};
 +use std::borrow::Cow;
 +use std::convert::TryInto;
 +use std::fmt::Display;
 +use std::ops::{Add, Neg, Not, Sub};
 +
 +/// A helper type to build suggestion correctly handling parenthesis.
 +#[derive(Clone, PartialEq)]
 +pub enum Sugg<'a> {
 +    /// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
 +    NonParen(Cow<'a, str>),
 +    /// An expression that does not fit in other variants.
 +    MaybeParen(Cow<'a, str>),
 +    /// A binary operator expression, including `as`-casts and explicit type
 +    /// coercion.
 +    BinOp(AssocOp, Cow<'a, str>),
 +}
 +
 +/// Literal constant `0`, for convenience.
 +pub const ZERO: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("0"));
 +/// Literal constant `1`, for convenience.
 +pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1"));
 +/// a constant represents an empty string, for convenience.
 +pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));
 +
 +impl Display for Sugg<'_> {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
 +        match *self {
 +            Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => s.fmt(f),
 +        }
 +    }
 +}
 +
 +#[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method
 +impl<'a> Sugg<'a> {
 +    /// Prepare a suggestion from an expression.
 +    pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
 +        snippet_opt(cx, expr.span).map(|snippet| {
 +            let snippet = Cow::Owned(snippet);
 +            Self::hir_from_snippet(expr, snippet)
 +        })
 +    }
 +
 +    /// Convenience function around `hir_opt` for suggestions with a default
 +    /// text.
 +    pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
 +        Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default)))
 +    }
 +
 +    /// Same as `hir`, but it adapts the applicability level by following rules:
 +    ///
 +    /// - Applicability level `Unspecified` will never be changed.
 +    /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 +    /// - If the default value is used and the applicability level is `MachineApplicable`, change it
 +    ///   to
 +    /// `HasPlaceholders`
 +    pub fn hir_with_applicability(
 +        cx: &LateContext<'_>,
 +        expr: &hir::Expr<'_>,
 +        default: &'a str,
 +        applicability: &mut Applicability,
 +    ) -> Self {
 +        if *applicability != Applicability::Unspecified && expr.span.from_expansion() {
 +            *applicability = Applicability::MaybeIncorrect;
 +        }
 +        Self::hir_opt(cx, expr).unwrap_or_else(|| {
 +            if *applicability == Applicability::MachineApplicable {
 +                *applicability = Applicability::HasPlaceholders;
 +            }
 +            Sugg::NonParen(Cow::Borrowed(default))
 +        })
 +    }
 +
 +    /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
 +    pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
 +        let snippet = snippet_with_macro_callsite(cx, expr.span, default);
 +
 +        Self::hir_from_snippet(expr, snippet)
 +    }
 +
 +    /// Same as `hir`, but first walks the span up to the given context. This will result in the
 +    /// macro call, rather then the expansion, if the span is from a child context. If the span is
 +    /// not from a child context, it will be used directly instead.
 +    ///
 +    /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
 +    /// node would result in `box []`. If given the context of the address of expression, this
 +    /// function will correctly get a snippet of `vec![]`.
 +    pub fn hir_with_context(
 +        cx: &LateContext<'_>,
 +        expr: &hir::Expr<'_>,
 +        ctxt: SyntaxContext,
 +        default: &'a str,
 +        applicability: &mut Applicability,
 +    ) -> Self {
 +        let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
 +
 +        if in_macro {
 +            Sugg::NonParen(snippet)
 +        } else {
 +            Self::hir_from_snippet(expr, snippet)
 +        }
 +    }
 +
 +    /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
 +    /// function variants of `Sugg`, since these use different snippet functions.
 +    fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
 +        if let Some(range) = higher::Range::hir(expr) {
 +            let op = match range.limits {
 +                ast::RangeLimits::HalfOpen => AssocOp::DotDot,
 +                ast::RangeLimits::Closed => AssocOp::DotDotEq,
 +            };
 +            return Sugg::BinOp(op, snippet);
 +        }
 +
 +        match expr.kind {
 +            hir::ExprKind::AddrOf(..)
 +            | hir::ExprKind::Box(..)
 +            | hir::ExprKind::If(..)
 +            | hir::ExprKind::Let(..)
 +            | hir::ExprKind::Closure(..)
 +            | hir::ExprKind::Unary(..)
 +            | hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
 +            hir::ExprKind::Continue(..)
 +            | hir::ExprKind::Yield(..)
 +            | hir::ExprKind::Array(..)
 +            | hir::ExprKind::Block(..)
 +            | hir::ExprKind::Break(..)
 +            | hir::ExprKind::Call(..)
 +            | hir::ExprKind::Field(..)
 +            | hir::ExprKind::Index(..)
 +            | hir::ExprKind::InlineAsm(..)
 +            | hir::ExprKind::LlvmInlineAsm(..)
 +            | hir::ExprKind::ConstBlock(..)
 +            | hir::ExprKind::Lit(..)
 +            | hir::ExprKind::Loop(..)
 +            | hir::ExprKind::MethodCall(..)
 +            | hir::ExprKind::Path(..)
 +            | hir::ExprKind::Repeat(..)
 +            | hir::ExprKind::Ret(..)
 +            | hir::ExprKind::Struct(..)
 +            | hir::ExprKind::Tup(..)
 +            | hir::ExprKind::DropTemps(_)
 +            | hir::ExprKind::Err => Sugg::NonParen(snippet),
 +            hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
 +            hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
 +            hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node.into()), snippet),
 +            hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
 +            hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
 +        }
 +    }
 +
 +    /// Prepare a suggestion from an expression.
 +    pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
 +        use rustc_ast::ast::RangeLimits;
 +
 +        let snippet = if expr.span.from_expansion() {
 +            snippet_with_macro_callsite(cx, expr.span, default)
 +        } else {
 +            snippet(cx, expr.span, default)
 +        };
 +
 +        match expr.kind {
 +            ast::ExprKind::AddrOf(..)
 +            | ast::ExprKind::Box(..)
 +            | ast::ExprKind::Closure(..)
 +            | ast::ExprKind::If(..)
 +            | ast::ExprKind::Let(..)
 +            | ast::ExprKind::Unary(..)
 +            | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
 +            ast::ExprKind::Async(..)
 +            | ast::ExprKind::Block(..)
 +            | ast::ExprKind::Break(..)
 +            | ast::ExprKind::Call(..)
 +            | ast::ExprKind::Continue(..)
 +            | ast::ExprKind::Yield(..)
 +            | ast::ExprKind::Field(..)
 +            | ast::ExprKind::ForLoop(..)
 +            | ast::ExprKind::Index(..)
 +            | ast::ExprKind::InlineAsm(..)
 +            | ast::ExprKind::LlvmInlineAsm(..)
 +            | ast::ExprKind::ConstBlock(..)
 +            | ast::ExprKind::Lit(..)
 +            | ast::ExprKind::Loop(..)
 +            | ast::ExprKind::MacCall(..)
 +            | ast::ExprKind::MethodCall(..)
 +            | ast::ExprKind::Paren(..)
 +            | ast::ExprKind::Underscore
 +            | ast::ExprKind::Path(..)
 +            | ast::ExprKind::Repeat(..)
 +            | ast::ExprKind::Ret(..)
 +            | ast::ExprKind::Struct(..)
 +            | ast::ExprKind::Try(..)
 +            | ast::ExprKind::TryBlock(..)
 +            | ast::ExprKind::Tup(..)
 +            | ast::ExprKind::Array(..)
 +            | ast::ExprKind::While(..)
 +            | ast::ExprKind::Await(..)
 +            | ast::ExprKind::Err => Sugg::NonParen(snippet),
 +            ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
 +            ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet),
 +            ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
 +            ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet),
 +            ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet),
 +            ast::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
 +            ast::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
 +        }
 +    }
 +
 +    /// Convenience method to create the `<lhs> && <rhs>` suggestion.
 +    pub fn and(self, rhs: &Self) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::And, &self, rhs)
 +    }
 +
 +    /// Convenience method to create the `<lhs> & <rhs>` suggestion.
 +    pub fn bit_and(self, rhs: &Self) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::BitAnd, &self, rhs)
 +    }
 +
 +    /// Convenience method to create the `<lhs> as <rhs>` suggestion.
 +    pub fn as_ty<R: Display>(self, rhs: R) -> Sugg<'static> {
 +        make_assoc(AssocOp::As, &self, &Sugg::NonParen(rhs.to_string().into()))
 +    }
 +
 +    /// Convenience method to create the `&<expr>` suggestion.
 +    pub fn addr(self) -> Sugg<'static> {
 +        make_unop("&", self)
 +    }
 +
 +    /// Convenience method to create the `&mut <expr>` suggestion.
 +    pub fn mut_addr(self) -> Sugg<'static> {
 +        make_unop("&mut ", self)
 +    }
 +
 +    /// Convenience method to create the `*<expr>` suggestion.
 +    pub fn deref(self) -> Sugg<'static> {
 +        make_unop("*", self)
 +    }
 +
 +    /// Convenience method to create the `&*<expr>` suggestion. Currently this
 +    /// is needed because `sugg.deref().addr()` produces an unnecessary set of
 +    /// parentheses around the deref.
 +    pub fn addr_deref(self) -> Sugg<'static> {
 +        make_unop("&*", self)
 +    }
 +
 +    /// Convenience method to create the `&mut *<expr>` suggestion. Currently
 +    /// this is needed because `sugg.deref().mut_addr()` produces an unnecessary
 +    /// set of parentheses around the deref.
 +    pub fn mut_addr_deref(self) -> Sugg<'static> {
 +        make_unop("&mut *", self)
 +    }
 +
 +    /// Convenience method to transform suggestion into a return call
 +    pub fn make_return(self) -> Sugg<'static> {
 +        Sugg::NonParen(Cow::Owned(format!("return {}", self)))
 +    }
 +
 +    /// Convenience method to transform suggestion into a block
 +    /// where the suggestion is a trailing expression
 +    pub fn blockify(self) -> Sugg<'static> {
 +        Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
 +    }
 +
 +    /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
 +    /// suggestion.
 +    #[allow(dead_code)]
 +    pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
 +        match limit {
 +            ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end),
 +            ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, end),
 +        }
 +    }
 +
 +    /// Adds parenthesis to any expression that might need them. Suitable to the
 +    /// `self` argument of a method call
 +    /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
 +    pub fn maybe_par(self) -> Self {
 +        match self {
 +            Sugg::NonParen(..) => self,
 +            // `(x)` and `(x).y()` both don't need additional parens.
 +            Sugg::MaybeParen(sugg) => {
 +                if has_enclosing_paren(&sugg) {
 +                    Sugg::MaybeParen(sugg)
 +                } else {
 +                    Sugg::NonParen(format!("({})", sugg).into())
 +                }
 +            },
 +            Sugg::BinOp(_, sugg) => {
 +                if has_enclosing_paren(&sugg) {
 +                    Sugg::NonParen(sugg)
 +                } else {
 +                    Sugg::NonParen(format!("({})", sugg).into())
 +                }
 +            },
 +        }
 +    }
 +}
 +
 +/// Return `true` if `sugg` is enclosed in parenthesis.
 +fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
 +    let mut chars = sugg.as_ref().chars();
++    if chars.next() == Some('(') {
 +        let mut depth = 1;
 +        for c in &mut chars {
 +            if c == '(' {
 +                depth += 1;
 +            } else if c == ')' {
 +                depth -= 1;
 +            }
 +            if depth == 0 {
 +                break;
 +            }
 +        }
 +        chars.next().is_none()
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Copied from the rust standard library, and then edited
 +macro_rules! forward_binop_impls_to_ref {
 +    (impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => {
 +        impl $imp<$t> for &$t {
 +            type Output = $o;
 +
 +            fn $method(self, other: $t) -> $o {
 +                $imp::$method(self, &other)
 +            }
 +        }
 +
 +        impl $imp<&$t> for $t {
 +            type Output = $o;
 +
 +            fn $method(self, other: &$t) -> $o {
 +                $imp::$method(&self, other)
 +            }
 +        }
 +
 +        impl $imp for $t {
 +            type Output = $o;
 +
 +            fn $method(self, other: $t) -> $o {
 +                $imp::$method(&self, &other)
 +            }
 +        }
 +    };
 +}
 +
 +impl Add for &Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn add(self, rhs: &Sugg<'_>) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::Add, self, rhs)
 +    }
 +}
 +
 +impl Sub for &Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn sub(self, rhs: &Sugg<'_>) -> Sugg<'static> {
 +        make_binop(ast::BinOpKind::Sub, self, rhs)
 +    }
 +}
 +
 +forward_binop_impls_to_ref!(impl Add, add for Sugg<'_>, type Output = Sugg<'static>);
 +forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'static>);
 +
 +impl Neg for Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn neg(self) -> Sugg<'static> {
 +        make_unop("-", self)
 +    }
 +}
 +
 +impl Not for Sugg<'_> {
 +    type Output = Sugg<'static>;
 +    fn not(self) -> Sugg<'static> {
 +        make_unop("!", self)
 +    }
 +}
 +
 +/// Helper type to display either `foo` or `(foo)`.
 +struct ParenHelper<T> {
 +    /// `true` if parentheses are needed.
 +    paren: bool,
 +    /// The main thing to display.
 +    wrapped: T,
 +}
 +
 +impl<T> ParenHelper<T> {
 +    /// Builds a `ParenHelper`.
 +    fn new(paren: bool, wrapped: T) -> Self {
 +        Self { paren, wrapped }
 +    }
 +}
 +
 +impl<T: Display> Display for ParenHelper<T> {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
 +        if self.paren {
 +            write!(f, "({})", self.wrapped)
 +        } else {
 +            self.wrapped.fmt(f)
 +        }
 +    }
 +}
 +
 +/// Builds the string for `<op><expr>` adding parenthesis when necessary.
 +///
 +/// For convenience, the operator is taken as a string because all unary
 +/// operators have the same
 +/// precedence.
 +pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
 +    Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into())
 +}
 +
 +/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
 +///
 +/// Precedence of shift operator relative to other arithmetic operation is
 +/// often confusing so
 +/// parenthesis will always be added for a mix of these.
 +pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
 +    /// Returns `true` if the operator is a shift operator `<<` or `>>`.
 +    fn is_shift(op: AssocOp) -> bool {
 +        matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
 +    }
 +
 +    /// Returns `true` if the operator is an arithmetic operator
 +    /// (i.e., `+`, `-`, `*`, `/`, `%`).
 +    fn is_arith(op: AssocOp) -> bool {
 +        matches!(
 +            op,
 +            AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
 +        )
 +    }
 +
 +    /// Returns `true` if the operator `op` needs parenthesis with the operator
 +    /// `other` in the direction `dir`.
 +    fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool {
 +        other.precedence() < op.precedence()
 +            || (other.precedence() == op.precedence()
 +                && ((op != other && associativity(op) != dir)
 +                    || (op == other && associativity(op) != Associativity::Both)))
 +            || is_shift(op) && is_arith(other)
 +            || is_shift(other) && is_arith(op)
 +    }
 +
 +    let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
 +        needs_paren(op, lop, Associativity::Left)
 +    } else {
 +        false
 +    };
 +
 +    let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
 +        needs_paren(op, rop, Associativity::Right)
 +    } else {
 +        false
 +    };
 +
 +    let lhs = ParenHelper::new(lhs_paren, lhs);
 +    let rhs = ParenHelper::new(rhs_paren, rhs);
 +    let sugg = match op {
 +        AssocOp::Add
 +        | AssocOp::BitAnd
 +        | AssocOp::BitOr
 +        | AssocOp::BitXor
 +        | AssocOp::Divide
 +        | AssocOp::Equal
 +        | AssocOp::Greater
 +        | AssocOp::GreaterEqual
 +        | AssocOp::LAnd
 +        | AssocOp::LOr
 +        | AssocOp::Less
 +        | AssocOp::LessEqual
 +        | AssocOp::Modulus
 +        | AssocOp::Multiply
 +        | AssocOp::NotEqual
 +        | AssocOp::ShiftLeft
 +        | AssocOp::ShiftRight
 +        | AssocOp::Subtract => format!(
 +            "{} {} {}",
 +            lhs,
 +            op.to_ast_binop().expect("Those are AST ops").to_string(),
 +            rhs
 +        ),
 +        AssocOp::Assign => format!("{} = {}", lhs, rhs),
 +        AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs),
 +        AssocOp::As => format!("{} as {}", lhs, rhs),
 +        AssocOp::DotDot => format!("{}..{}", lhs, rhs),
 +        AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
 +        AssocOp::Colon => format!("{}: {}", lhs, rhs),
 +    };
 +
 +    Sugg::BinOp(op, sugg.into())
 +}
 +
 +/// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`.
 +pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
 +    make_assoc(AssocOp::from_ast_binop(op), lhs, rhs)
 +}
 +
 +#[derive(PartialEq, Eq, Clone, Copy)]
 +/// Operator associativity.
 +enum Associativity {
 +    /// The operator is both left-associative and right-associative.
 +    Both,
 +    /// The operator is left-associative.
 +    Left,
 +    /// The operator is not associative.
 +    None,
 +    /// The operator is right-associative.
 +    Right,
 +}
 +
 +/// Returns the associativity/fixity of an operator. The difference with
 +/// `AssocOp::fixity` is that an operator can be both left and right associative
 +/// (such as `+`: `a + b + c == (a + b) + c == a + (b + c)`.
 +///
 +/// Chained `as` and explicit `:` type coercion never need inner parenthesis so
 +/// they are considered
 +/// associative.
 +#[must_use]
 +fn associativity(op: AssocOp) -> Associativity {
 +    use rustc_ast::util::parser::AssocOp::{
 +        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater,
 +        GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
 +    };
 +
 +    match op {
 +        Assign | AssignOp(_) => Associativity::Right,
 +        Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
 +        Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
 +        | Subtract => Associativity::Left,
 +        DotDot | DotDotEq => Associativity::None,
 +    }
 +}
 +
 +/// Converts a `hir::BinOp` to the corresponding assigning binary operator.
 +fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
 +    use rustc_ast::token::BinOpToken::{And, Caret, Minus, Or, Percent, Plus, Shl, Shr, Slash, Star};
 +
 +    AssocOp::AssignOp(match op.node {
 +        hir::BinOpKind::Add => Plus,
 +        hir::BinOpKind::BitAnd => And,
 +        hir::BinOpKind::BitOr => Or,
 +        hir::BinOpKind::BitXor => Caret,
 +        hir::BinOpKind::Div => Slash,
 +        hir::BinOpKind::Mul => Star,
 +        hir::BinOpKind::Rem => Percent,
 +        hir::BinOpKind::Shl => Shl,
 +        hir::BinOpKind::Shr => Shr,
 +        hir::BinOpKind::Sub => Minus,
 +
 +        hir::BinOpKind::And
 +        | hir::BinOpKind::Eq
 +        | hir::BinOpKind::Ge
 +        | hir::BinOpKind::Gt
 +        | hir::BinOpKind::Le
 +        | hir::BinOpKind::Lt
 +        | hir::BinOpKind::Ne
 +        | hir::BinOpKind::Or => panic!("This operator does not exist"),
 +    })
 +}
 +
 +/// Converts an `ast::BinOp` to the corresponding assigning binary operator.
 +fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
 +    use rustc_ast::ast::BinOpKind::{
 +        Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
 +    };
 +    use rustc_ast::token::BinOpToken;
 +
 +    AssocOp::AssignOp(match op.node {
 +        Add => BinOpToken::Plus,
 +        BitAnd => BinOpToken::And,
 +        BitOr => BinOpToken::Or,
 +        BitXor => BinOpToken::Caret,
 +        Div => BinOpToken::Slash,
 +        Mul => BinOpToken::Star,
 +        Rem => BinOpToken::Percent,
 +        Shl => BinOpToken::Shl,
 +        Shr => BinOpToken::Shr,
 +        Sub => BinOpToken::Minus,
 +        And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"),
 +    })
 +}
 +
 +/// Returns the indentation before `span` if there are nothing but `[ \t]`
 +/// before it on its line.
 +fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 +    let lo = cx.sess().source_map().lookup_char_pos(span.lo());
 +    lo.file
 +        .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */)
 +        .and_then(|line| {
 +            if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
 +                // We can mix char and byte positions here because we only consider `[ \t]`.
 +                if lo.col == CharPos(pos) {
 +                    Some(line[..pos].into())
 +                } else {
 +                    None
 +                }
 +            } else {
 +                None
 +            }
 +        })
 +}
 +
 +/// Convenience extension trait for `DiagnosticBuilder`.
 +pub trait DiagnosticBuilderExt<T: LintContext> {
 +    /// Suggests to add an attribute to an item.
 +    ///
 +    /// Correctly handles indentation of the attribute and item.
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_item_with_attr(cx, item, "#[derive(Default)]");
 +    /// ```
 +    fn suggest_item_with_attr<D: Display + ?Sized>(
 +        &mut self,
 +        cx: &T,
 +        item: Span,
 +        msg: &str,
 +        attr: &D,
 +        applicability: Applicability,
 +    );
 +
 +    /// Suggest to add an item before another.
 +    ///
 +    /// The item should not be indented (except for inner indentation).
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_prepend_item(cx, item,
 +    /// "fn foo() {
 +    ///     bar();
 +    /// }");
 +    /// ```
 +    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability);
 +
 +    /// Suggest to completely remove an item.
 +    ///
 +    /// This will remove an item and all following whitespace until the next non-whitespace
 +    /// character. This should work correctly if item is on the same indentation level as the
 +    /// following item.
 +    ///
 +    /// # Example
 +    ///
 +    /// ```rust,ignore
 +    /// diag.suggest_remove_item(cx, item, "remove this")
 +    /// ```
 +    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
 +}
 +
 +impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> {
 +    fn suggest_item_with_attr<D: Display + ?Sized>(
 +        &mut self,
 +        cx: &T,
 +        item: Span,
 +        msg: &str,
 +        attr: &D,
 +        applicability: Applicability,
 +    ) {
 +        if let Some(indent) = indentation(cx, item) {
 +            let span = item.with_hi(item.lo());
 +
 +            self.span_suggestion(span, msg, format!("{}\n{}", attr, indent), applicability);
 +        }
 +    }
 +
 +    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability) {
 +        if let Some(indent) = indentation(cx, item) {
 +            let span = item.with_hi(item.lo());
 +
 +            let mut first = true;
 +            let new_item = new_item
 +                .lines()
 +                .map(|l| {
 +                    if first {
 +                        first = false;
 +                        format!("{}\n", l)
 +                    } else {
 +                        format!("{}{}\n", indent, l)
 +                    }
 +                })
 +                .collect::<String>();
 +
 +            self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent), applicability);
 +        }
 +    }
 +
 +    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability) {
 +        let mut remove_span = item;
 +        let hi = cx.sess().source_map().next_point(remove_span).hi();
 +        let fmpos = cx.sess().source_map().lookup_byte_offset(hi);
 +
 +        if let Some(ref src) = fmpos.sf.src {
 +            let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
 +
 +            if let Some(non_whitespace_offset) = non_whitespace_offset {
 +                remove_span = remove_span
 +                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
 +            }
 +        }
 +
 +        self.span_suggestion(remove_span, msg, String::new(), applicability);
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::Sugg;
 +
 +    use rustc_ast::util::parser::AssocOp;
 +    use std::borrow::Cow;
 +
 +    const SUGGESTION: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("function_call()"));
 +
 +    #[test]
 +    fn make_return_transform_sugg_into_a_return_call() {
 +        assert_eq!("return function_call()", SUGGESTION.make_return().to_string());
 +    }
 +
 +    #[test]
 +    fn blockify_transforms_sugg_into_a_block() {
 +        assert_eq!("{ function_call() }", SUGGESTION.blockify().to_string());
 +    }
 +
 +    #[test]
 +    fn binop_maybe_par() {
 +        let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into());
 +        assert_eq!("(1 + 1)", sugg.maybe_par().to_string());
 +
 +        let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1) + (1 + 1)".into());
 +        assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string());
 +    }
 +}
index 96cb8a4dae43ead3fe5cd9f54756e4ba7df04da0,0000000000000000000000000000000000000000..6ebe1a0028a315fff24a116237b52c245cf0ac5f
mode 100644,000000..100644
--- /dev/null
@@@ -1,369 -1,0 +1,369 @@@
- /// Returns true iff the given type is a non aggregate primitive (a bool or char, any integer or
- /// floating-point number type). For checking aggregation of primitive types (e.g. tuples and slices
- /// of primitive type) see `is_recursively_primitive_type`
 +//! Util methods for [`rustc_middle::ty`]
 +
 +#![allow(clippy::module_name_repetitions)]
 +
 +use rustc_ast::ast::Mutability;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir as hir;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{TyKind, Unsafety};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 +use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
 +use rustc_span::sym;
 +use rustc_span::symbol::{Ident, Symbol};
 +use rustc_span::DUMMY_SP;
 +use rustc_trait_selection::infer::InferCtxtExt;
 +use rustc_trait_selection::traits::query::normalize::AtExt;
 +
 +use crate::{match_def_path, must_use_attr};
 +
 +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 whether a type can be partially moved.
 +pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    if has_drop(cx, ty) || is_copy(cx, ty) {
 +        return false;
 +    }
 +    match ty.kind() {
 +        ty::Param(_) => false,
 +        ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))),
 +        _ => true,
 +    }
 +}
 +
 +/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
 +pub fn contains_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool {
 +    ty.walk(tcx).any(|inner| match inner.unpack() {
 +        GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty),
 +        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
 +    })
 +}
 +
 +/// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 +/// constructor.
 +pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tcx AdtDef) -> bool {
 +    ty.walk(tcx).any(|inner| match inner.unpack() {
 +        GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt),
 +        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
 +    })
 +}
 +
 +/// Resolves `<T as Iterator>::Item` for `T`
 +/// Do not invoke without first verifying that the type implements `Iterator`
 +pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 +    cx.tcx
 +        .get_diagnostic_item(sym::Iterator)
 +        .and_then(|iter_did| {
 +            cx.tcx.associated_items(iter_did).find_by_name_and_kind(
 +                cx.tcx,
 +                Ident::from_str("Item"),
 +                ty::AssocKind::Type,
 +                iter_did,
 +            )
 +        })
 +        .map(|assoc| {
 +            let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[]));
 +            cx.tcx.normalize_erasing_regions(cx.param_env, proj)
 +        })
 +}
 +
 +/// Returns true if ty has `iter` or `iter_mut` methods
 +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> {
 +    // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
 +    // exists and has the desired signature. Unfortunately FnCtxt is not exported
 +    // so we can't use its `lookup_method` method.
 +    let into_iter_collections: &[Symbol] = &[
 +        sym::Vec,
 +        sym::Option,
 +        sym::Result,
 +        sym::BTreeMap,
 +        sym::BTreeSet,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::BinaryHeap,
 +        sym::HashSet,
 +        sym::HashMap,
 +        sym::PathBuf,
 +        sym::Path,
 +        sym::Receiver,
 +    ];
 +
 +    let ty_to_check = match probably_ref_ty.kind() {
 +        ty::Ref(_, ty_to_check, _) => ty_to_check,
 +        _ => probably_ref_ty,
 +    };
 +
 +    let def_id = match ty_to_check.kind() {
 +        ty::Array(..) => return Some(sym::array),
 +        ty::Slice(..) => return Some(sym::slice),
 +        ty::Adt(adt, _) => adt.did,
 +        _ => return None,
 +    };
 +
 +    for &name in into_iter_collections {
 +        if cx.tcx.is_diagnostic_item(name, def_id) {
 +            return Some(cx.tcx.item_name(def_id));
 +        }
 +    }
 +    None
 +}
 +
 +/// Checks whether a type implements a trait.
 +/// The function returns false in case the type contains an inference variable.
 +/// See also [`get_trait_def_id`](super::get_trait_def_id).
 +pub fn implements_trait<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_id: DefId,
 +    ty_params: &[GenericArg<'tcx>],
 +) -> bool {
 +    // Clippy shouldn't have infer types
 +    assert!(!ty.needs_infer());
 +
 +    let ty = cx.tcx.erase_regions(ty);
 +    if ty.has_escaping_bound_vars() {
 +        return false;
 +    }
 +    let ty_params = cx.tcx.mk_substs(ty_params.iter());
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        infcx
 +            .type_implements_trait(trait_id, ty, ty_params, cx.param_env)
 +            .must_apply_modulo_regions()
 +    })
 +}
 +
 +/// Checks whether this type implements `Drop`.
 +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.ty_adt_def() {
 +        Some(def) => def.has_dtor(cx.tcx),
 +        None => false,
 +    }
 +}
 +
 +// Returns whether the type has #[must_use] attribute
 +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => 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(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
 +            // for the Array case we don't need to care for the len == 0 case
 +            // because we don't want to lint functions returning empty arrays
 +            is_must_use_ty(cx, *ty)
 +        },
 +        ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
 +        ty::Opaque(ref def_id, _) => {
 +            for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
 +                if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
 +                    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.iter() {
 +                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
 +                    if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        _ => false,
 +    }
 +}
 +
 +// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
 +// this function can be removed once the `normalize` method does not panic when normalization does
 +// not succeed
 +/// Checks if `Ty` is normalizable. This function is useful
 +/// to avoid crashes on `layout_of`.
 +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
 +    is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
 +}
 +
 +fn is_normalizable_helper<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    param_env: ty::ParamEnv<'tcx>,
 +    ty: Ty<'tcx>,
 +    cache: &mut FxHashMap<Ty<'tcx>, bool>,
 +) -> bool {
 +    if let Some(&cached_result) = cache.get(ty) {
 +        return cached_result;
 +    }
 +    // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
 +    cache.insert(ty, false);
 +    let result = cx.tcx.infer_ctxt().enter(|infcx| {
 +        let cause = rustc_middle::traits::ObligationCause::dummy();
 +        if infcx.at(&cause, param_env).normalize(ty).is_ok() {
 +            match ty.kind() {
 +                ty::Adt(def, substs) => def.variants.iter().all(|variant| {
 +                    variant
 +                        .fields
 +                        .iter()
 +                        .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
 +                }),
 +                _ => ty.walk(cx.tcx).all(|generic_arg| match generic_arg.unpack() {
 +                    GenericArgKind::Type(inner_ty) if inner_ty != ty => {
 +                        is_normalizable_helper(cx, param_env, inner_ty, cache)
 +                    },
 +                    _ => true, // if inner_ty == ty, we've already checked it
 +                }),
 +            }
 +        } else {
 +            false
 +        }
 +    });
 +    cache.insert(ty, result);
 +    result
 +}
 +
- /// Returns true 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).
++/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
++/// integer or floating-point number type). For checking aggregation of primitive types (e.g.
++/// tuples and slices of primitive type) see `is_recursively_primitive_type`
 +pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool {
 +    matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_))
 +}
 +
++/// Returns `true` if the given type is a primitive (a `bool` or `char`, any integer or
++/// floating-point number type, a `str`, or an array, slice, or tuple of those types).
 +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 +    match ty.kind() {
 +        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
 +        ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
 +        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
 +        ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is a reference equals to a diagnostic item
 +pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind() {
 +        ty::Ref(_, ref_ty, _) => match ref_ty.kind() {
 +            ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
 +            _ => false,
 +        },
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a diagnostic item
 +///
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a lang item.
 +///
 +/// Returns `false` if the `LangItem` is not defined.
 +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).map_or(false, |li| li == adt.did),
 +        _ => false,
 +    }
 +}
 +
 +/// Return `true` if the passed `typ` is `isize` or `usize`.
 +pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
 +    matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 +}
 +
 +/// Checks if type is struct, enum or union type with the given def path.
 +///
 +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
 +        _ => false,
 +    }
 +}
 +
 +/// Peels off all references on the type. Returns the underlying type and the number of references
 +/// removed.
 +pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
 +        if let ty::Ref(_, ty, _) = ty.kind() {
 +            peel(ty, count + 1)
 +        } else {
 +            (ty, count)
 +        }
 +    }
 +    peel(ty, 0)
 +}
 +
 +/// Peels off all references on the type.Returns the underlying type, the number of references
 +/// removed, and whether the pointer is ultimately mutable or not.
 +pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
 +    fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
 +        match ty.kind() {
 +            ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability),
 +            ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not),
 +            _ => (ty, count, mutability),
 +        }
 +    }
 +    f(ty, 0, Mutability::Mut)
 +}
 +
 +/// Returns `true` if the given type is an `unsafe` function.
 +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
 +        _ => false,
 +    }
 +}
 +
 +/// Returns the base type for HIR references and pointers.
 +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 +    match ty.kind {
 +        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
 +        _ => ty,
 +    }
 +}
 +
 +/// Returns the base type for references and raw pointers, and count reference
 +/// depth.
 +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
 +        match ty.kind() {
 +            ty::Ref(_, ty, _) => inner(ty, depth + 1),
 +            _ => (ty, depth),
 +        }
 +    }
 +    inner(ty, 0)
 +}
 +
 +/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
 +/// otherwise returns `false`
 +pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 +    match (&a.kind(), &b.kind()) {
 +        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
 +            if did_a != did_b {
 +                return false;
 +            }
 +
 +            substs_a
 +                .iter()
 +                .zip(substs_b.iter())
 +                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
 +                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
 +                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
 +                        same_type_and_consts(type_a, type_b)
 +                    },
 +                    _ => true,
 +                })
 +        },
 +        _ => a == b,
 +    }
 +}
index 098ec175fe2d91fcf530df7b6885c81d64e42fa1,0000000000000000000000000000000000000000..34206b5ae2b21a14291aa6c3c7c2af0f9b579d11
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,243 @@@
-         if let ty::BorrowKind::MutBorrow = bk {
 +use crate as utils;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::HirIdSet;
 +use rustc_hir::{Expr, ExprKind, HirId};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::mir::FakeReadCause;
 +use rustc_middle::ty;
 +use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 +
 +/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 +pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
 +    let mut delegate = MutVarsDelegate {
 +        used_mutably: HirIdSet::default(),
 +        skip: false,
 +    };
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        ExprUseVisitor::new(
 +            &mut delegate,
 +            &infcx,
 +            expr.hir_id.owner,
 +            cx.param_env,
 +            cx.typeck_results(),
 +        )
 +        .walk_expr(expr);
 +    });
 +
 +    if delegate.skip {
 +        return None;
 +    }
 +    Some(delegate.used_mutably)
 +}
 +
 +pub fn is_potentially_mutated<'tcx>(variable: HirId, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
 +    mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&variable))
 +}
 +
 +struct MutVarsDelegate {
 +    used_mutably: HirIdSet,
 +    skip: bool,
 +}
 +
 +impl<'tcx> MutVarsDelegate {
 +    #[allow(clippy::similar_names)]
 +    fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
 +        match cat.place.base {
 +            PlaceBase::Local(id) => {
 +                self.used_mutably.insert(id);
 +            },
 +            PlaceBase::Upvar(_) => {
 +                //FIXME: This causes false negatives. We can't get the `NodeId` from
 +                //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
 +                //`while`-body, not just the ones in the condition.
 +                self.skip = true;
 +            },
 +            _ => {},
 +        }
 +    }
 +}
 +
 +impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
 +    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 +
 +    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
++        if bk == ty::BorrowKind::MutBorrow {
 +            self.update(cmt);
 +        }
 +    }
 +
 +    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
 +        self.update(cmt);
 +    }
 +
 +    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
 +}
 +
 +pub struct ParamBindingIdCollector {
 +    binding_hir_ids: Vec<hir::HirId>,
 +}
 +impl<'tcx> ParamBindingIdCollector {
 +    fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
 +        let mut hir_ids: Vec<hir::HirId> = Vec::new();
 +        for param in body.params.iter() {
 +            let mut finder = ParamBindingIdCollector {
 +                binding_hir_ids: Vec::new(),
 +            };
 +            finder.visit_param(param);
 +            for hir_id in &finder.binding_hir_ids {
 +                hir_ids.push(*hir_id);
 +            }
 +        }
 +        hir_ids
 +    }
 +}
 +impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
 +        if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind {
 +            self.binding_hir_ids.push(hir_id);
 +        }
 +        intravisit::walk_pat(self, pat);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +        intravisit::NestedVisitorMap::None
 +    }
 +}
 +
 +pub struct BindingUsageFinder<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    binding_ids: Vec<hir::HirId>,
 +    usage_found: bool,
 +}
 +impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
 +    pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool {
 +        let mut finder = BindingUsageFinder {
 +            cx,
 +            binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body),
 +            usage_found: false,
 +        };
 +        finder.visit_body(body);
 +        finder.usage_found
 +    }
 +}
 +impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
 +        if !self.usage_found {
 +            intravisit::walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
 +        if let hir::def::Res::Local(id) = path.res {
 +            if self.binding_ids.contains(&id) {
 +                self.usage_found = true;
 +            }
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +        intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +struct ReturnBreakContinueMacroVisitor {
 +    seen_return_break_continue: bool,
 +}
 +
 +impl ReturnBreakContinueMacroVisitor {
 +    fn new() -> ReturnBreakContinueMacroVisitor {
 +        ReturnBreakContinueMacroVisitor {
 +            seen_return_break_continue: false,
 +        }
 +    }
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
 +    type Map = Map<'tcx>;
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
 +        if self.seen_return_break_continue {
 +            // No need to look farther if we've already seen one of them
 +            return;
 +        }
 +        match &ex.kind {
 +            ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => {
 +                self.seen_return_break_continue = true;
 +            },
 +            // Something special could be done here to handle while or for loop
 +            // desugaring, as this will detect a break if there's a while loop
 +            // or a for loop inside the expression.
 +            _ => {
 +                if utils::in_macro(ex.span) {
 +                    self.seen_return_break_continue = true;
 +                } else {
 +                    rustc_hir::intravisit::walk_expr(self, ex);
 +                }
 +            },
 +        }
 +    }
 +}
 +
 +pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
 +    let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new();
 +    recursive_visitor.visit_expr(expression);
 +    recursive_visitor.seen_return_break_continue
 +}
 +
 +pub struct UsedAfterExprVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    expr: &'tcx Expr<'tcx>,
 +    definition: HirId,
 +    past_expr: bool,
 +    used_after_expr: bool,
 +}
 +impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> {
 +    pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +        utils::path_to_local(expr).map_or(false, |definition| {
 +            let mut visitor = UsedAfterExprVisitor {
 +                cx,
 +                expr,
 +                definition,
 +                past_expr: false,
 +                used_after_expr: false,
 +            };
 +            utils::get_enclosing_block(cx, definition).map_or(false, |block| {
 +                visitor.visit_block(block);
 +                visitor.used_after_expr
 +            })
 +        })
 +    }
 +}
 +
 +impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 +        if self.used_after_expr {
 +            return;
 +        }
 +
 +        if expr.hir_id == self.expr.hir_id {
 +            self.past_expr = true;
 +        } else if self.past_expr && utils::path_to_local_id(expr, self.definition) {
 +            self.used_after_expr = true;
 +        } else {
 +            intravisit::walk_expr(self, expr);
 +        }
 +    }
 +}
index 660401ff28c5de4ac6f38defee3da72e3cc48575,0000000000000000000000000000000000000000..f98819303e6827c80e373954d725f0483de628d2
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-09-28"
 +[toolchain]
++channel = "nightly-2021-10-07"
 +components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
index d7596f6ff0cae9e7e78f9c72b438ebb55da6e2e5,0000000000000000000000000000000000000000..e8b1640c8693e5907cf93e491a713658b17e6a63
mode 100644,000000..100644
--- /dev/null
@@@ -1,340 -1,0 +1,342 @@@
-         "dependencies not found in depinfo: {:?}",
 +#![feature(test)] // compiletest_rs requires this attribute
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +
 +use compiletest_rs as compiletest;
 +use compiletest_rs::common::Mode as TestMode;
 +
 +use std::collections::HashMap;
 +use std::env::{self, remove_var, set_var, var_os};
 +use std::ffi::{OsStr, OsString};
 +use std::fs;
 +use std::io;
 +use std::path::{Path, PathBuf};
 +
 +mod cargo;
 +
 +// whether to run internal tests or not
 +const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");
 +
 +/// All crates used in UI tests are listed here
 +static TEST_DEPENDENCIES: &[&str] = &[
 +    "clippy_utils",
 +    "derive_new",
 +    "if_chain",
 +    "itertools",
 +    "quote",
 +    "regex",
 +    "serde",
 +    "serde_derive",
 +    "syn",
 +];
 +
 +// Test dependencies may need an `extern crate` here to ensure that they show up
 +// in the depinfo file (otherwise cargo thinks they are unused)
 +#[allow(unused_extern_crates)]
 +extern crate clippy_utils;
 +#[allow(unused_extern_crates)]
 +extern crate derive_new;
 +#[allow(unused_extern_crates)]
 +extern crate if_chain;
 +#[allow(unused_extern_crates)]
 +extern crate itertools;
 +#[allow(unused_extern_crates)]
 +extern crate quote;
 +#[allow(unused_extern_crates)]
 +extern crate syn;
 +
 +/// Produces a string with an `--extern` flag for all UI test crate
 +/// dependencies.
 +///
 +/// The dependency files are located by parsing the depinfo file for this test
 +/// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test
 +/// dependencies must be added to Cargo.toml at the project root. Test
 +/// dependencies that are not *directly* used by this test module require an
 +/// `extern crate` declaration.
 +fn extern_flags() -> String {
 +    let current_exe_depinfo = {
 +        let mut path = env::current_exe().unwrap();
 +        path.set_extension("d");
 +        std::fs::read_to_string(path).unwrap()
 +    };
 +    let mut crates: HashMap<&str, &str> = HashMap::with_capacity(TEST_DEPENDENCIES.len());
 +    for line in current_exe_depinfo.lines() {
 +        // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:`
 +        let parse_name_path = || {
 +            if line.starts_with(char::is_whitespace) {
 +                return None;
 +            }
 +            let path_str = line.strip_suffix(':')?;
 +            let path = Path::new(path_str);
 +            if !matches!(path.extension()?.to_str()?, "rlib" | "so" | "dylib" | "dll") {
 +                return None;
 +            }
 +            let (name, _hash) = path.file_stem()?.to_str()?.rsplit_once('-')?;
 +            // the "lib" prefix is not present for dll files
 +            let name = name.strip_prefix("lib").unwrap_or(name);
 +            Some((name, path_str))
 +        };
 +        if let Some((name, path)) = parse_name_path() {
 +            if TEST_DEPENDENCIES.contains(&name) {
 +                // A dependency may be listed twice if it is available in sysroot,
 +                // and the sysroot dependencies are listed first. As of the writing,
 +                // this only seems to apply to if_chain.
 +                crates.insert(name, path);
 +            }
 +        }
 +    }
 +    let not_found: Vec<&str> = TEST_DEPENDENCIES
 +        .iter()
 +        .copied()
 +        .filter(|n| !crates.contains_key(n))
 +        .collect();
 +    assert!(
 +        not_found.is_empty(),
++        "dependencies not found in depinfo: {:?}\n\
++        help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\
++        help: Try adding to dev-dependencies in Cargo.toml",
 +        not_found
 +    );
 +    crates
 +        .into_iter()
 +        .map(|(name, path)| format!(" --extern {}={}", name, path))
 +        .collect()
 +}
 +
 +fn default_config() -> compiletest::Config {
 +    let mut config = compiletest::Config::default();
 +
 +    if let Ok(filters) = env::var("TESTNAME") {
 +        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
 +    }
 +
 +    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
 +        let path = PathBuf::from(path);
 +        config.run_lib_path = path.clone();
 +        config.compile_lib_path = path;
 +    }
 +    let current_exe_path = std::env::current_exe().unwrap();
 +    let deps_path = current_exe_path.parent().unwrap();
 +    let profile_path = deps_path.parent().unwrap();
 +
 +    // Using `-L dependency={}` enforces that external dependencies are added with `--extern`.
 +    // This is valuable because a) it allows us to monitor what external dependencies are used
 +    // and b) it ensures that conflicting rlibs are resolved properly.
 +    let host_libs = option_env!("HOST_LIBS")
 +        .map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display()))
 +        .unwrap_or_default();
 +    config.target_rustcflags = Some(format!(
 +        "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}",
 +        deps_path.display(),
 +        host_libs,
 +        extern_flags(),
 +    ));
 +
 +    config.build_base = profile_path.join("test");
 +    config.rustc_path = profile_path.join(if cfg!(windows) {
 +        "clippy-driver.exe"
 +    } else {
 +        "clippy-driver"
 +    });
 +    config
 +}
 +
 +fn run_ui(cfg: &mut compiletest::Config) {
 +    cfg.mode = TestMode::Ui;
 +    cfg.src_base = Path::new("tests").join("ui");
 +    // use tests/clippy.toml
 +    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
 +    compiletest::run_tests(cfg);
 +}
 +
 +fn run_internal_tests(cfg: &mut compiletest::Config) {
 +    // only run internal tests with the internal-tests feature
 +    if !RUN_INTERNAL_TESTS {
 +        return;
 +    }
 +    cfg.mode = TestMode::Ui;
 +    cfg.src_base = Path::new("tests").join("ui-internal");
 +    compiletest::run_tests(cfg);
 +}
 +
 +fn run_ui_toml(config: &mut compiletest::Config) {
 +    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
 +        let mut result = true;
 +        let opts = compiletest::test_opts(config);
 +        for dir in fs::read_dir(&config.src_base)? {
 +            let dir = dir?;
 +            if !dir.file_type()?.is_dir() {
 +                continue;
 +            }
 +            let dir_path = dir.path();
 +            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
 +            for file in fs::read_dir(&dir_path)? {
 +                let file = file?;
 +                let file_path = file.path();
 +                if file.file_type()?.is_dir() {
 +                    continue;
 +                }
 +                if file_path.extension() != Some(OsStr::new("rs")) {
 +                    continue;
 +                }
 +                let paths = compiletest::common::TestPaths {
 +                    file: file_path,
 +                    base: config.src_base.clone(),
 +                    relative_dir: dir_path.file_name().unwrap().into(),
 +                };
 +                let test_name = compiletest::make_test_name(config, &paths);
 +                let index = tests
 +                    .iter()
 +                    .position(|test| test.desc.name == test_name)
 +                    .expect("The test should be in there");
 +                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
 +            }
 +        }
 +        Ok(result)
 +    }
 +
 +    config.mode = TestMode::Ui;
 +    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();
 +
 +    let tests = compiletest::make_tests(config);
 +
 +    let res = run_tests(config, tests);
 +    match res {
 +        Ok(true) => {},
 +        Ok(false) => panic!("Some tests failed"),
 +        Err(e) => {
 +            panic!("I/O failure during tests: {:?}", e);
 +        },
 +    }
 +}
 +
 +fn run_ui_cargo(config: &mut compiletest::Config) {
 +    fn run_tests(
 +        config: &compiletest::Config,
 +        filters: &[String],
 +        mut tests: Vec<tester::TestDescAndFn>,
 +    ) -> Result<bool, io::Error> {
 +        let mut result = true;
 +        let opts = compiletest::test_opts(config);
 +
 +        for dir in fs::read_dir(&config.src_base)? {
 +            let dir = dir?;
 +            if !dir.file_type()?.is_dir() {
 +                continue;
 +            }
 +
 +            // Use the filter if provided
 +            let dir_path = dir.path();
 +            for filter in filters {
 +                if !dir_path.ends_with(filter) {
 +                    continue;
 +                }
 +            }
 +
 +            for case in fs::read_dir(&dir_path)? {
 +                let case = case?;
 +                if !case.file_type()?.is_dir() {
 +                    continue;
 +                }
 +
 +                let src_path = case.path().join("src");
 +
 +                // When switching between branches, if the previous branch had a test
 +                // that the current branch does not have, the directory is not removed
 +                // because an ignored Cargo.lock file exists.
 +                if !src_path.exists() {
 +                    continue;
 +                }
 +
 +                env::set_current_dir(&src_path)?;
 +                for file in fs::read_dir(&src_path)? {
 +                    let file = file?;
 +                    if file.file_type()?.is_dir() {
 +                        continue;
 +                    }
 +
 +                    // Search for the main file to avoid running a test for each file in the project
 +                    let file_path = file.path();
 +                    match file_path.file_name().and_then(OsStr::to_str) {
 +                        Some("main.rs") => {},
 +                        _ => continue,
 +                    }
 +                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
 +                    let paths = compiletest::common::TestPaths {
 +                        file: file_path,
 +                        base: config.src_base.clone(),
 +                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
 +                    };
 +                    let test_name = compiletest::make_test_name(config, &paths);
 +                    let index = tests
 +                        .iter()
 +                        .position(|test| test.desc.name == test_name)
 +                        .expect("The test should be in there");
 +                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
 +                }
 +            }
 +        }
 +        Ok(result)
 +    }
 +
 +    if cargo::is_rustc_test_suite() {
 +        return;
 +    }
 +
 +    config.mode = TestMode::Ui;
 +    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();
 +
 +    let tests = compiletest::make_tests(config);
 +
 +    let current_dir = env::current_dir().unwrap();
 +    let res = run_tests(config, &config.filters, tests);
 +    env::set_current_dir(current_dir).unwrap();
 +
 +    match res {
 +        Ok(true) => {},
 +        Ok(false) => panic!("Some tests failed"),
 +        Err(e) => {
 +            panic!("I/O failure during tests: {:?}", e);
 +        },
 +    }
 +}
 +
 +fn prepare_env() {
 +    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
 +    set_var("__CLIPPY_INTERNAL_TESTS", "true");
 +    //set_var("RUST_BACKTRACE", "0");
 +}
 +
 +#[test]
 +fn compile_test() {
 +    prepare_env();
 +    let mut config = default_config();
 +    run_ui(&mut config);
 +    run_ui_toml(&mut config);
 +    run_ui_cargo(&mut config);
 +    run_internal_tests(&mut config);
 +}
 +
 +/// Restores an env var on drop
 +#[must_use]
 +struct VarGuard {
 +    key: &'static str,
 +    value: Option<OsString>,
 +}
 +
 +impl VarGuard {
 +    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
 +        let value = var_os(key);
 +        set_var(key, val);
 +        Self { key, value }
 +    }
 +}
 +
 +impl Drop for VarGuard {
 +    fn drop(&mut self) {
 +        match self.value.as_deref() {
 +            None => remove_var(self.key),
 +            Some(value) => set_var(self.key, value),
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a942709d14acc27da4706e23760346122169525f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++enable-raw-pointer-heuristic-for-send = false
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..90c2439dc34f4556322f383bc0e672c6069618dc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++#![warn(clippy::non_send_fields_in_send_ty)]
++#![feature(extern_types)]
++
++use std::rc::Rc;
++
++// Basic tests should not be affected
++pub struct NoGeneric {
++    rc_is_not_send: Rc<String>,
++}
++
++unsafe impl Send for NoGeneric {}
++
++pub struct MultiField<T> {
++    field1: T,
++    field2: T,
++    field3: T,
++}
++
++unsafe impl<T> Send for MultiField<T> {}
++
++pub enum MyOption<T> {
++    MySome(T),
++    MyNone,
++}
++
++unsafe impl<T> Send for MyOption<T> {}
++
++// All fields are disallowed when raw pointer heuristic is off
++extern "C" {
++    type NonSend;
++}
++
++pub struct HeuristicTest {
++    field1: Vec<*const NonSend>,
++    field2: [*const NonSend; 3],
++    field3: (*const NonSend, *const NonSend, *const NonSend),
++    field4: (*const NonSend, Rc<u8>),
++    field5: Vec<Vec<*const NonSend>>,
++}
++
++unsafe impl Send for HeuristicTest {}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b07f9dd3df30e02b4ae6f95ac8d802905fe9855c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,91 @@@
++error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
++  --> $DIR/test.rs:11:1
++   |
++LL | unsafe impl Send for NoGeneric {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++   = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
++note: the type of field `rc_is_not_send` is `!Send`
++  --> $DIR/test.rs:8:5
++   |
++LL |     rc_is_not_send: Rc<String>,
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++
++error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
++  --> $DIR/test.rs:19:1
++   |
++LL | unsafe impl<T> Send for MultiField<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field1` is `!Send`
++  --> $DIR/test.rs:14:5
++   |
++LL |     field1: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++note: the type of field `field2` is `!Send`
++  --> $DIR/test.rs:15:5
++   |
++LL |     field2: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++note: the type of field `field3` is `!Send`
++  --> $DIR/test.rs:16:5
++   |
++LL |     field3: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
++  --> $DIR/test.rs:26:1
++   |
++LL | unsafe impl<T> Send for MyOption<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `0` is `!Send`
++  --> $DIR/test.rs:22:12
++   |
++LL |     MySome(T),
++   |            ^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
++  --> $DIR/test.rs:41:1
++   |
++LL | unsafe impl Send for HeuristicTest {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field1` is `!Send`
++  --> $DIR/test.rs:34:5
++   |
++LL |     field1: Vec<*const NonSend>,
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++note: the type of field `field2` is `!Send`
++  --> $DIR/test.rs:35:5
++   |
++LL |     field2: [*const NonSend; 3],
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++note: the type of field `field3` is `!Send`
++  --> $DIR/test.rs:36:5
++   |
++LL |     field3: (*const NonSend, *const NonSend, *const NonSend),
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++note: the type of field `field4` is `!Send`
++  --> $DIR/test.rs:37:5
++   |
++LL |     field4: (*const NonSend, Rc<u8>),
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++note: the type of field `field5` is `!Send`
++  --> $DIR/test.rs:38:5
++   |
++LL |     field5: Vec<Vec<*const NonSend>>,
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++
++error: aborting due to 4 previous errors
++
index e0029ebeb27ac4ad94966097b9c02f5914e9a4b5,0000000000000000000000000000000000000000..97bab1308aa52b12d94e269117263ef330ab1d0d
mode 100644,000000..100644
--- /dev/null
@@@ -1,4 -1,0 +1,4 @@@
- error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `third-party` at line 5 column 1
++error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `third-party` at line 5 column 1
 +
 +error: aborting due to previous error
 +
index 2ae4d613507edce8b3c5c3145b6354c85fe64ba6,0000000000000000000000000000000000000000..ccdbd34f7ec7bb587980db53285bded7fe1ddb32
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,64 @@@
- #[allow(unused, clippy::shadow_unrelated, clippy::similar_names)]
 +#[warn(clippy::approx_constant)]
++#[allow(clippy::similar_names)]
 +fn main() {
 +    let my_e = 2.7182;
 +    let almost_e = 2.718;
 +    let no_e = 2.71;
 +
 +    let my_1_frac_pi = 0.3183;
 +    let no_1_frac_pi = 0.31;
 +
 +    let my_frac_1_sqrt_2 = 0.70710678;
 +    let almost_frac_1_sqrt_2 = 0.70711;
 +    let my_frac_1_sqrt_2 = 0.707;
 +
 +    let my_frac_2_pi = 0.63661977;
 +    let no_frac_2_pi = 0.636;
 +
 +    let my_frac_2_sq_pi = 1.128379;
 +    let no_frac_2_sq_pi = 1.128;
 +
 +    let my_frac_pi_2 = 1.57079632679;
 +    let no_frac_pi_2 = 1.5705;
 +
 +    let my_frac_pi_3 = 1.04719755119;
 +    let no_frac_pi_3 = 1.047;
 +
 +    let my_frac_pi_4 = 0.785398163397;
 +    let no_frac_pi_4 = 0.785;
 +
 +    let my_frac_pi_6 = 0.523598775598;
 +    let no_frac_pi_6 = 0.523;
 +
 +    let my_frac_pi_8 = 0.3926990816987;
 +    let no_frac_pi_8 = 0.392;
 +
 +    let my_ln_10 = 2.302585092994046;
 +    let no_ln_10 = 2.303;
 +
 +    let my_ln_2 = 0.6931471805599453;
 +    let no_ln_2 = 0.693;
 +
 +    let my_log10_e = 0.4342944819032518;
 +    let no_log10_e = 0.434;
 +
 +    let my_log2_e = 1.4426950408889634;
 +    let no_log2_e = 1.442;
 +
 +    let log2_10 = 3.321928094887362;
 +    let no_log2_10 = 3.321;
 +
 +    let log10_2 = 0.301029995663981;
 +    let no_log10_2 = 0.301;
 +
 +    let my_pi = 3.1415;
 +    let almost_pi = 3.14;
 +    let no_pi = 3.15;
 +
 +    let my_sq2 = 1.4142;
 +    let no_sq2 = 1.414;
 +
 +    let my_tau = 6.2832;
 +    let almost_tau = 6.28;
 +    let no_tau = 6.3;
 +}
index ce2040bdeb82d934e2bbe8c7fbd7bbb63d959835,0000000000000000000000000000000000000000..12f550d9c9a805ad8023cb11ea8223529c53ff92
mode 100644,000000..100644
--- /dev/null
@@@ -1,223 -1,0 +1,223 @@@
- #![allow(dead_code)]
++#![allow(dead_code, clippy::equatable_if_let)]
 +#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
 +
 +// This tests the branches_sharing_code lint at the end of blocks
 +
 +fn simple_examples() {
 +    let x = 1;
 +
 +    let _ = if x == 7 {
 +        println!("Branch I");
 +        let start_value = 0;
 +        println!("=^.^=");
 +
 +        // Same but not moveable due to `start_value`
 +        let _ = start_value;
 +
 +        // The rest is self contained and moveable => Only lint the rest
 +        let result = false;
 +        println!("Block end!");
 +        result
 +    } else {
 +        println!("Branch II");
 +        let start_value = 8;
 +        println!("xD");
 +
 +        // Same but not moveable due to `start_value`
 +        let _ = start_value;
 +
 +        // The rest is self contained and moveable => Only lint the rest
 +        let result = false;
 +        println!("Block end!");
 +        result
 +    };
 +
 +    // Else if block
 +    if x == 9 {
 +        println!("The index is: 6");
 +
 +        println!("Same end of block");
 +    } else if x == 8 {
 +        println!("The index is: 4");
 +
 +        // We should only get a lint trigger for the last statement
 +        println!("This is also eq with the else block");
 +        println!("Same end of block");
 +    } else {
 +        println!("This is also eq with the else block");
 +        println!("Same end of block");
 +    }
 +
 +    // Use of outer scope value
 +    let outer_scope_value = "I'm outside the if block";
 +    if x < 99 {
 +        let z = "How are you";
 +        println!("I'm a local because I use the value `z`: `{}`", z);
 +
 +        println!(
 +            "I'm moveable because I know: `outer_scope_value`: '{}'",
 +            outer_scope_value
 +        );
 +    } else {
 +        let z = 45678000;
 +        println!("I'm a local because I use the value `z`: `{}`", z);
 +
 +        println!(
 +            "I'm moveable because I know: `outer_scope_value`: '{}'",
 +            outer_scope_value
 +        );
 +    }
 +
 +    if x == 9 {
 +        if x == 8 {
 +            // No parent!!
 +            println!("---");
 +            println!("Hello World");
 +        } else {
 +            println!("Hello World");
 +        }
 +    }
 +}
 +
 +/// Simple examples where the move can cause some problems due to moved values
 +fn simple_but_suggestion_is_invalid() {
 +    let x = 16;
 +
 +    // Local value
 +    let later_used_value = 17;
 +    if x == 9 {
 +        let _ = 9;
 +        let later_used_value = "A string value";
 +        println!("{}", later_used_value);
 +    } else {
 +        let later_used_value = "A string value";
 +        println!("{}", later_used_value);
 +        // I'm expecting a note about this
 +    }
 +    println!("{}", later_used_value);
 +
 +    // outer function
 +    if x == 78 {
 +        let simple_examples = "I now identify as a &str :)";
 +        println!("This is the new simple_example: {}", simple_examples);
 +    } else {
 +        println!("Separator print statement");
 +
 +        let simple_examples = "I now identify as a &str :)";
 +        println!("This is the new simple_example: {}", simple_examples);
 +    }
 +    simple_examples();
 +}
 +
 +/// Tests where the blocks are not linted due to the used value scope
 +fn not_moveable_due_to_value_scope() {
 +    let x = 18;
 +
 +    // Using a local value in the moved code
 +    if x == 9 {
 +        let y = 18;
 +        println!("y is: `{}`", y);
 +    } else {
 +        let y = "A string";
 +        println!("y is: `{}`", y);
 +    }
 +
 +    // Using a local value in the expression
 +    let _ = if x == 0 {
 +        let mut result = x + 1;
 +
 +        println!("1. Doing some calculations");
 +        println!("2. Some more calculations");
 +        println!("3. Setting result");
 +
 +        result
 +    } else {
 +        let mut result = x - 1;
 +
 +        println!("1. Doing some calculations");
 +        println!("2. Some more calculations");
 +        println!("3. Setting result");
 +
 +        result
 +    };
 +
 +    let _ = if x == 7 {
 +        let z1 = 100;
 +        println!("z1: {}", z1);
 +
 +        let z2 = z1;
 +        println!("z2: {}", z2);
 +
 +        z2
 +    } else {
 +        let z1 = 300;
 +        println!("z1: {}", z1);
 +
 +        let z2 = z1;
 +        println!("z2: {}", z2);
 +
 +        z2
 +    };
 +}
 +
 +/// This should add a note to the lint msg since the moved expression is not `()`
 +fn added_note_for_expression_use() -> u32 {
 +    let x = 9;
 +
 +    let _ = if x == 7 {
 +        x << 2
 +    } else {
 +        let _ = 6;
 +        x << 2
 +    };
 +
 +    if x == 9 {
 +        x * 4
 +    } else {
 +        let _ = 17;
 +        x * 4
 +    }
 +}
 +
 +#[rustfmt::skip]
 +fn test_suggestion_with_weird_formatting() {
 +    let x = 9;
 +    let mut a = 0;
 +    let mut b = 0;
 +
 +    // The error message still looks weird tbh but this is the best I can do
 +    // for weird formatting
 +    if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
 +}
 +
 +fn fp_test() {
 +    let x = 17;
 +
 +    if x == 18 {
 +        let y = 19;
 +        if y < x {
 +            println!("Trigger")
 +        }
 +    } else {
 +        let z = 166;
 +        if z < x {
 +            println!("Trigger")
 +        }
 +    }
 +}
 +
 +fn fp_if_let_issue7054() {
 +    // This shouldn't trigger the lint
 +    let string;
 +    let _x = if let true = true {
 +        ""
 +    } else if true {
 +        string = "x".to_owned();
 +        &string
 +    } else {
 +        string = "y".to_owned();
 +        &string
 +    };
 +}
 +
 +fn main() {}
index c69a46f0a77ee908e908d67c821782776c6f8cc1,0000000000000000000000000000000000000000..bb6c4c0703d5168579216e7b37fd571e94570d52
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,77 @@@
- #![allow(clippy::assertions_on_constants)]
 +// run-rustfix
++#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
 +
 +#[rustfmt::skip]
 +#[warn(clippy::collapsible_if)]
 +#[warn(clippy::collapsible_else_if)]
 +
 +fn main() {
 +    let x = "hello";
 +    let y = "world";
 +    // Collapse `else { if .. }` to `else if ..`
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else if y == "world" {
 +        println!("world!")
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else if let Some(42) = Some(42) {
 +        println!("world!")
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else if y == "world" {
 +        println!("world")
 +    }
 +    else {
 +        println!("!")
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else if let Some(42) = Some(42) {
 +        println!("world")
 +    }
 +    else {
 +        println!("!")
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else if let Some(42) = Some(42) {
 +        println!("world")
 +    }
 +    else {
 +        println!("!")
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else if x == "hello" {
 +        println!("world")
 +    }
 +    else {
 +        println!("!")
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else if let Some(42) = Some(42) {
 +        println!("world")
 +    }
 +    else {
 +        println!("!")
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        #[cfg(not(roflol))]
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +}
index 1359c7eb6278e6dbda3ee8f937fe8acc835a4258,0000000000000000000000000000000000000000..6d4f688db8c0a7a80114ea1e2842f914fc94881c
mode 100644,000000..100644
--- /dev/null
@@@ -1,91 -1,0 +1,91 @@@
- #![allow(clippy::assertions_on_constants)]
 +// run-rustfix
++#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
 +
 +#[rustfmt::skip]
 +#[warn(clippy::collapsible_if)]
 +#[warn(clippy::collapsible_else_if)]
 +
 +fn main() {
 +    let x = "hello";
 +    let y = "world";
 +    // Collapse `else { if .. }` to `else if ..`
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        if let Some(42) = Some(42) {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        if y == "world" {
 +            println!("world")
 +        }
 +        else {
 +            println!("!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        if let Some(42) = Some(42) {
 +            println!("world")
 +        }
 +        else {
 +            println!("!")
 +        }
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else {
 +        if let Some(42) = Some(42) {
 +            println!("world")
 +        }
 +        else {
 +            println!("!")
 +        }
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else {
 +        if x == "hello" {
 +            println!("world")
 +        }
 +        else {
 +            println!("!")
 +        }
 +    }
 +
 +    if let Some(42) = Some(42) {
 +        print!("Hello ");
 +    } else {
 +        if let Some(42) = Some(42) {
 +            println!("world")
 +        }
 +        else {
 +            println!("!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        #[cfg(not(roflol))]
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +}
index e4c088bf6f03f3bf5402af00d503bff56965340f,0000000000000000000000000000000000000000..5b0e4a473c4ad708d167625ed559ec49c1cb6b35
mode 100644,000000..100644
--- /dev/null
@@@ -1,148 -1,0 +1,148 @@@
- #![allow(clippy::assertions_on_constants)]
 +// run-rustfix
++#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
 +
 +#[rustfmt::skip]
 +#[warn(clippy::collapsible_if)]
 +fn main() {
 +    let x = "hello";
 +    let y = "world";
 +    if x == "hello" && y == "world" {
 +        println!("Hello world!");
 +    }
 +
 +    if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
 +        println!("Hello world!");
 +    }
 +
 +    if x == "hello" && x == "world" && (y == "world" || y == "hello") {
 +        println!("Hello world!");
 +    }
 +
 +    if (x == "hello" || x == "world") && y == "world" && y == "hello" {
 +        println!("Hello world!");
 +    }
 +
 +    if x == "hello" && x == "world" && y == "world" && y == "hello" {
 +        println!("Hello world!");
 +    }
 +
 +    if 42 == 1337 && 'a' != 'A' {
 +        println!("world!")
 +    }
 +
 +    // Works because any if with an else statement cannot be collapsed.
 +    if x == "hello" {
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    } else {
 +        println!("Not Hello world");
 +    }
 +
 +    if x == "hello" {
 +        if y == "world" {
 +            println!("Hello world!");
 +        } else {
 +            println!("Hello something else");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +
 +    if true {
 +    } else {
 +        assert!(true); // assert! is just an `if`
 +    }
 +
 +
 +    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
 +    if x == "hello" {// Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" { // Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        // Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" && y == "world" { // Collapsible
 +        println!("Hello world!");
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        // Not collapsible
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        // Not collapsible
 +        if let Some(42) = Some(42) {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        /* Not collapsible */
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" { /* Not collapsible */
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    // Test behavior wrt. `let_chains`.
 +    // None of the cases below should be collapsed.
 +    fn truth() -> bool { true }
 +
 +    // Prefix:
 +    if let 0 = 1 {
 +        if truth() {}
 +    }
 +
 +    // Suffix:
 +    if truth() {
 +        if let 0 = 1 {}
 +    }
 +
 +    // Midfix:
 +    if truth() {
 +        if let 0 = 1 {
 +            if truth() {}
 +        }
 +    }
 +
 +    // Fix #5962
 +    if matches!(true, true) && matches!(true, true) {}
 +
 +    if true {
 +        #[cfg(not(teehee))]
 +        if true {
 +            println!("Hello world!");
 +        }
 +    }
 +}
index d6cf01c8319400c844ecedf0f2eea401c3c67fdf,0000000000000000000000000000000000000000..cd231a5d7abb0852161d0dab921956d654ae73b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,164 -1,0 +1,164 @@@
- #![allow(clippy::assertions_on_constants)]
 +// run-rustfix
++#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
 +
 +#[rustfmt::skip]
 +#[warn(clippy::collapsible_if)]
 +fn main() {
 +    let x = "hello";
 +    let y = "world";
 +    if x == "hello" {
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" || x == "world" {
 +        if y == "world" || y == "hello" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" && x == "world" {
 +        if y == "world" || y == "hello" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" || x == "world" {
 +        if y == "world" && y == "hello" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" && x == "world" {
 +        if y == "world" && y == "hello" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if 42 == 1337 {
 +        if 'a' != 'A' {
 +            println!("world!")
 +        }
 +    }
 +
 +    // Works because any if with an else statement cannot be collapsed.
 +    if x == "hello" {
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    } else {
 +        println!("Not Hello world");
 +    }
 +
 +    if x == "hello" {
 +        if y == "world" {
 +            println!("Hello world!");
 +        } else {
 +            println!("Hello something else");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +
 +    if true {
 +    } else {
 +        assert!(true); // assert! is just an `if`
 +    }
 +
 +
 +    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
 +    if x == "hello" {// Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" { // Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        // Not collapsible
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        if y == "world" { // Collapsible
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        // Not collapsible
 +        if y == "world" {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        print!("Hello ");
 +    } else {
 +        // Not collapsible
 +        if let Some(42) = Some(42) {
 +            println!("world!")
 +        }
 +    }
 +
 +    if x == "hello" {
 +        /* Not collapsible */
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    if x == "hello" { /* Not collapsible */
 +        if y == "world" {
 +            println!("Hello world!");
 +        }
 +    }
 +
 +    // Test behavior wrt. `let_chains`.
 +    // None of the cases below should be collapsed.
 +    fn truth() -> bool { true }
 +
 +    // Prefix:
 +    if let 0 = 1 {
 +        if truth() {}
 +    }
 +
 +    // Suffix:
 +    if truth() {
 +        if let 0 = 1 {}
 +    }
 +
 +    // Midfix:
 +    if truth() {
 +        if let 0 = 1 {
 +            if truth() {}
 +        }
 +    }
 +
 +    // Fix #5962
 +    if matches!(true, true) {
 +        if matches!(true, true) {}
 +    }
 +
 +    if true {
 +        #[cfg(not(teehee))]
 +        if true {
 +            println!("Hello world!");
 +        }
 +    }
 +}
index 4ce365cc7649ab0a405e472535caada9f65c5822,0000000000000000000000000000000000000000..603ae7dc9eb117308cdfa37116187803750c4927
mode 100644,000000..100644
--- /dev/null
@@@ -1,260 -1,0 +1,265 @@@
- #![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)]
 +#![warn(clippy::collapsible_match)]
++#![allow(
++    clippy::needless_return,
++    clippy::no_effect,
++    clippy::single_match,
++    clippy::equatable_if_let
++)]
 +
 +fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>) {
 +    // match without block
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // match with block
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // if let, if let
 +    if let Ok(val) = res_opt {
 +        if let Some(n) = val {
 +            take(n);
 +        }
 +    }
 +
 +    // if let else, if let else
 +    if let Ok(val) = res_opt {
 +        if let Some(n) = val {
 +            take(n);
 +        } else {
 +            return;
 +        }
 +    } else {
 +        return;
 +    }
 +
 +    // if let, match
 +    if let Ok(val) = res_opt {
 +        match val {
 +            Some(n) => foo(n),
 +            _ => (),
 +        }
 +    }
 +
 +    // match, if let
 +    match res_opt {
 +        Ok(val) => {
 +            if let Some(n) = val {
 +                take(n);
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    // if let else, match
 +    if let Ok(val) = res_opt {
 +        match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        }
 +    } else {
 +        return;
 +    }
 +
 +    // match, if let else
 +    match res_opt {
 +        Ok(val) => {
 +            if let Some(n) = val {
 +                take(n);
 +            } else {
 +                return;
 +            }
 +        },
 +        _ => return,
 +    }
 +
 +    // None in inner match same as outer wild branch
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(n) => foo(n),
 +            None => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // None in outer match same as inner wild branch
 +    match opt_opt {
 +        Some(val) => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        None => return,
 +    }
 +}
 +
 +fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u32, String>, String>) {
 +    while let Some(x) = make() {
 +        if let Some(1) = x {
 +            todo!();
 +        }
 +    }
 +    // no wild pattern in outer match
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        Err(_) => return,
 +    }
 +
 +    // inner branch is not wild or None
 +    match res_res {
 +        Ok(val) => match val {
 +            Ok(n) => foo(n),
 +            Err(_) => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // statement before inner match
 +    match res_opt {
 +        Ok(val) => {
 +            "hi buddy";
 +            match val {
 +                Some(n) => foo(n),
 +                _ => return,
 +            }
 +        },
 +        _ => return,
 +    }
 +
 +    // statement after inner match
 +    match res_opt {
 +        Ok(val) => {
 +            match val {
 +                Some(n) => foo(n),
 +                _ => return,
 +            }
 +            "hi buddy";
 +        },
 +        _ => return,
 +    }
 +
 +    // wild branches do not match
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(n) => foo(n),
 +            _ => {
 +                "sup";
 +                return;
 +            },
 +        },
 +        _ => return,
 +    }
 +
 +    // binding used in if guard
 +    match res_opt {
 +        Ok(val) if val.is_some() => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // binding used in inner match body
 +    match res_opt {
 +        Ok(val) => match val {
 +            Some(_) => take(val),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +
 +    // if guard on inner match
 +    {
 +        match res_opt {
 +            Ok(val) => match val {
 +                Some(n) if make() => foo(n),
 +                _ => return,
 +            },
 +            _ => return,
 +        }
 +        match res_opt {
 +            Ok(val) => match val {
 +                _ => make(),
 +                _ if make() => return,
 +            },
 +            _ => return,
 +        }
 +    }
 +
 +    // differing macro contexts
 +    {
 +        macro_rules! mac {
 +            ($val:ident) => {
 +                match $val {
 +                    Some(n) => foo(n),
 +                    _ => return,
 +                }
 +            };
 +        }
 +        match res_opt {
 +            Ok(val) => mac!(val),
 +            _ => return,
 +        }
 +    }
 +
 +    // OR pattern
 +    enum E<T> {
 +        A(T),
 +        B(T),
 +        C(T),
 +    };
 +    match make::<E<Option<u32>>>() {
 +        E::A(val) | E::B(val) => match val {
 +            Some(n) => foo(n),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +    match make::<Option<E<u32>>>() {
 +        Some(val) => match val {
 +            E::A(val) | E::B(val) => foo(val),
 +            _ => return,
 +        },
 +        _ => return,
 +    }
 +    if let Ok(val) = res_opt {
 +        if let Some(n) = val {
 +            let _ = || {
 +                // usage in closure
 +                println!("{:?}", val);
 +            };
 +        }
 +    }
 +    let _: &dyn std::any::Any = match &Some(Some(1)) {
 +        Some(e) => match e {
 +            Some(e) => e,
 +            e => e,
 +        },
 +        // else branch looks the same but the binding is different
 +        e => e,
 +    };
 +}
 +
 +fn make<T>() -> T {
 +    unimplemented!()
 +}
 +
 +fn foo<T, U>(t: T) -> U {
 +    unimplemented!()
 +}
 +
 +fn take<T>(t: T) {}
 +
 +fn main() {}
index c119570e8abd8eab585064870a28f3cfd8582938,0000000000000000000000000000000000000000..5f18b693502953a09d94d5cdcc10eb09a0bef905
mode 100644,000000..100644
--- /dev/null
@@@ -1,179 -1,0 +1,179 @@@
-   --> $DIR/collapsible_match.rs:7:20
 +error: this `match` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:7:12
++  --> $DIR/collapsible_match.rs:12:20
 +   |
 +LL |           Ok(val) => match val {
 +   |  ____________________^
 +LL | |             Some(n) => foo(n),
 +LL | |             _ => return,
 +LL | |         },
 +   | |_________^
 +   |
 +   = note: `-D clippy::collapsible-match` implied by `-D warnings`
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:16:20
++  --> $DIR/collapsible_match.rs:12:12
 +   |
 +LL |         Ok(val) => match val {
 +   |            ^^^ replace this binding
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: this `match` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:16:12
++  --> $DIR/collapsible_match.rs:21:20
 +   |
 +LL |           Ok(val) => match val {
 +   |  ____________________^
 +LL | |             Some(n) => foo(n),
 +LL | |             _ => return,
 +LL | |         },
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:25:9
++  --> $DIR/collapsible_match.rs:21:12
 +   |
 +LL |         Ok(val) => match val {
 +   |            ^^^ replace this binding
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: this `if let` can be collapsed into the outer `if let`
-   --> $DIR/collapsible_match.rs:24:15
++  --> $DIR/collapsible_match.rs:30:9
 +   |
 +LL | /         if let Some(n) = val {
 +LL | |             take(n);
 +LL | |         }
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:32:9
++  --> $DIR/collapsible_match.rs:29:15
 +   |
 +LL |     if let Ok(val) = res_opt {
 +   |               ^^^ replace this binding
 +LL |         if let Some(n) = val {
 +   |                ^^^^^^^ with this pattern
 +
 +error: this `if let` can be collapsed into the outer `if let`
-   --> $DIR/collapsible_match.rs:31:15
++  --> $DIR/collapsible_match.rs:37:9
 +   |
 +LL | /         if let Some(n) = val {
 +LL | |             take(n);
 +LL | |         } else {
 +LL | |             return;
 +LL | |         }
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:43:9
++  --> $DIR/collapsible_match.rs:36:15
 +   |
 +LL |     if let Ok(val) = res_opt {
 +   |               ^^^ replace this binding
 +LL |         if let Some(n) = val {
 +   |                ^^^^^^^ with this pattern
 +
 +error: this `match` can be collapsed into the outer `if let`
-   --> $DIR/collapsible_match.rs:42:15
++  --> $DIR/collapsible_match.rs:48:9
 +   |
 +LL | /         match val {
 +LL | |             Some(n) => foo(n),
 +LL | |             _ => (),
 +LL | |         }
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:52:13
++  --> $DIR/collapsible_match.rs:47:15
 +   |
 +LL |     if let Ok(val) = res_opt {
 +   |               ^^^ replace this binding
 +LL |         match val {
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: this `if let` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:51:12
++  --> $DIR/collapsible_match.rs:57:13
 +   |
 +LL | /             if let Some(n) = val {
 +LL | |                 take(n);
 +LL | |             }
 +   | |_____________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:61:9
++  --> $DIR/collapsible_match.rs:56:12
 +   |
 +LL |         Ok(val) => {
 +   |            ^^^ replace this binding
 +LL |             if let Some(n) = val {
 +   |                    ^^^^^^^ with this pattern
 +
 +error: this `match` can be collapsed into the outer `if let`
-   --> $DIR/collapsible_match.rs:60:15
++  --> $DIR/collapsible_match.rs:66:9
 +   |
 +LL | /         match val {
 +LL | |             Some(n) => foo(n),
 +LL | |             _ => return,
 +LL | |         }
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:72:13
++  --> $DIR/collapsible_match.rs:65:15
 +   |
 +LL |     if let Ok(val) = res_opt {
 +   |               ^^^ replace this binding
 +LL |         match val {
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: this `if let` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:71:12
++  --> $DIR/collapsible_match.rs:77:13
 +   |
 +LL | /             if let Some(n) = val {
 +LL | |                 take(n);
 +LL | |             } else {
 +LL | |                 return;
 +LL | |             }
 +   | |_____________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:83:20
++  --> $DIR/collapsible_match.rs:76:12
 +   |
 +LL |         Ok(val) => {
 +   |            ^^^ replace this binding
 +LL |             if let Some(n) = val {
 +   |                    ^^^^^^^ with this pattern
 +
 +error: this `match` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:83:12
++  --> $DIR/collapsible_match.rs:88:20
 +   |
 +LL |           Ok(val) => match val {
 +   |  ____________________^
 +LL | |             Some(n) => foo(n),
 +LL | |             None => return,
 +LL | |         },
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
-   --> $DIR/collapsible_match.rs:92:22
++  --> $DIR/collapsible_match.rs:88:12
 +   |
 +LL |         Ok(val) => match val {
 +   |            ^^^ replace this binding
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: this `match` can be collapsed into the outer `match`
-   --> $DIR/collapsible_match.rs:92:14
++  --> $DIR/collapsible_match.rs:97:22
 +   |
 +LL |           Some(val) => match val {
 +   |  ______________________^
 +LL | |             Some(n) => foo(n),
 +LL | |             _ => return,
 +LL | |         },
 +   | |_________^
 +   |
 +help: the outer pattern can be modified to include the inner pattern
++  --> $DIR/collapsible_match.rs:97:14
 +   |
 +LL |         Some(val) => match val {
 +   |              ^^^ replace this binding
 +LL |             Some(n) => foo(n),
 +   |             ^^^^^^^ with this pattern
 +
 +error: aborting due to 10 previous errors
 +
index 7d62e315da2fca1912c2c12a3651c4c8c59d1bac,0000000000000000000000000000000000000000..02c49aa0d7c1f4a0e9e8d2dd22c49cedbd9b2c88
mode 100644,000000..100644
--- /dev/null
@@@ -1,23 -1,0 +1,23 @@@
- #![allow(clippy::blacklisted_name)]
 +#![warn(clippy::all)]
++#![allow(clippy::blacklisted_name, clippy::equatable_if_let)]
 +#![allow(unused)]
 +
 +/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
 +
 +enum Foo {
 +    Bar,
 +    Baz,
 +}
 +
 +fn bar(foo: Foo) {
 +    macro_rules! baz {
 +        () => {
 +            if let Foo::Bar = foo {}
 +        };
 +    }
 +
 +    baz!();
 +    baz!();
 +}
 +
 +fn main() {}
index 1ed78547a60cd49a40f20493f9fcf964a3bc695c,0000000000000000000000000000000000000000..156c88e2e45b7d902e8dc3fa3f28f083210c2758
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,31 @@@
 +// ignore-windows
 +// ignore-macos
 +
 +#![feature(no_core, lang_items, start)]
 +#![no_core]
++#![allow(clippy::missing_safety_doc)]
 +
 +#[link(name = "c")]
 +extern "C" {}
 +
 +#[lang = "sized"]
 +pub trait Sized {}
 +#[lang = "copy"]
 +pub trait Copy {}
 +#[lang = "freeze"]
 +pub unsafe trait Freeze {}
 +
 +#[lang = "start"]
 +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
 +    0
 +}
 +
 +fn main() {}
 +
 +struct A;
 +
 +impl A {
 +    pub fn as_ref(self) -> &'static str {
 +        "A"
 +    }
 +}
index 6210d7c6cfd80c1d32369494f3010694b606dc65,0000000000000000000000000000000000000000..40d355e9a2e3e871bbe730bb01b6e4e440652bf3
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
-   --> $DIR/def_id_nocore.rs:27:19
 +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
++  --> $DIR/def_id_nocore.rs:28:19
 +   |
 +LL |     pub fn as_ref(self) -> &'static str {
 +   |                   ^^^^
 +   |
 +   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 +   = help: consider choosing a less ambiguous name
 +
 +error: aborting due to previous error
 +
index ebbc0c77e32656caae3a17245d8042c2de0f6af3,0000000000000000000000000000000000000000..a6412004726d33302d4e65a26d2fef3221fafb67
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,243 @@@
 +use std::collections::HashMap;
 +
 +struct FooDefault<'a> {
 +    a: bool,
 +    b: i32,
 +    c: u64,
 +    d: Vec<i32>,
 +    e: FooND1,
 +    f: FooND2,
 +    g: HashMap<i32, i32>,
 +    h: (i32, Vec<i32>),
 +    i: [Vec<i32>; 3],
 +    j: [i32; 5],
 +    k: Option<i32>,
 +    l: &'a [i32],
 +}
 +
 +impl std::default::Default for FooDefault<'_> {
 +    fn default() -> Self {
 +        Self {
 +            a: false,
 +            b: 0,
 +            c: 0u64,
 +            d: vec![],
 +            e: Default::default(),
 +            f: FooND2::default(),
 +            g: HashMap::new(),
 +            h: (0, vec![]),
 +            i: [vec![], vec![], vec![]],
 +            j: [0; 5],
 +            k: None,
 +            l: &[],
 +        }
 +    }
 +}
 +
 +struct TupleDefault(bool, i32, u64);
 +
 +impl std::default::Default for TupleDefault {
 +    fn default() -> Self {
 +        Self(false, 0, 0u64)
 +    }
 +}
 +
 +struct FooND1 {
 +    a: bool,
 +}
 +
 +impl std::default::Default for FooND1 {
 +    fn default() -> Self {
 +        Self { a: true }
 +    }
 +}
 +
 +struct FooND2 {
 +    a: i32,
 +}
 +
 +impl std::default::Default for FooND2 {
 +    fn default() -> Self {
 +        Self { a: 5 }
 +    }
 +}
 +
 +struct FooNDNew {
 +    a: bool,
 +}
 +
 +impl FooNDNew {
 +    fn new() -> Self {
 +        Self { a: true }
 +    }
 +}
 +
 +impl Default for FooNDNew {
 +    fn default() -> Self {
 +        Self::new()
 +    }
 +}
 +
 +struct FooNDVec(Vec<i32>);
 +
 +impl Default for FooNDVec {
 +    fn default() -> Self {
 +        Self(vec![5, 12])
 +    }
 +}
 +
 +struct StrDefault<'a>(&'a str);
 +
 +impl Default for StrDefault<'_> {
 +    fn default() -> Self {
 +        Self("")
 +    }
 +}
 +
 +#[derive(Default)]
 +struct AlreadyDerived(i32, bool);
 +
 +macro_rules! mac {
 +    () => {
 +        0
 +    };
 +    ($e:expr) => {
 +        struct X(u32);
 +        impl Default for X {
 +            fn default() -> Self {
 +                Self($e)
 +            }
 +        }
 +    };
 +}
 +
 +mac!(0);
 +
 +struct Y(u32);
 +impl Default for Y {
 +    fn default() -> Self {
 +        Self(mac!())
 +    }
 +}
 +
 +struct RustIssue26925<T> {
 +    a: Option<T>,
 +}
 +
 +// We should watch out for cases where a manual impl is needed because a
 +// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925).
 +// For example, a struct with Option<T> does not require T: Default, but a derive adds
 +// that type bound anyways. So until #26925 get fixed we should disable lint
 +// for the following case
 +impl<T> Default for RustIssue26925<T> {
 +    fn default() -> Self {
 +        Self { a: None }
 +    }
 +}
 +
 +struct SpecializedImpl<A, B> {
 +    a: A,
 +    b: B,
 +}
 +
 +impl<T: Default> Default for SpecializedImpl<T, T> {
 +    fn default() -> Self {
 +        Self {
 +            a: T::default(),
 +            b: T::default(),
 +        }
 +    }
 +}
 +
 +struct WithoutSelfCurly {
 +    a: bool,
 +}
 +
 +impl Default for WithoutSelfCurly {
 +    fn default() -> Self {
 +        WithoutSelfCurly { a: false }
 +    }
 +}
 +
 +struct WithoutSelfParan(bool);
 +
 +impl Default for WithoutSelfParan {
 +    fn default() -> Self {
 +        WithoutSelfParan(false)
 +    }
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/7655
 +
 +pub struct SpecializedImpl2<T> {
 +    v: Vec<T>,
 +}
 +
 +impl Default for SpecializedImpl2<String> {
 +    fn default() -> Self {
 +        Self { v: Vec::new() }
 +    }
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/7654
 +
 +pub struct Color {
 +    pub r: u8,
 +    pub g: u8,
 +    pub b: u8,
 +}
 +
 +/// `#000000`
 +impl Default for Color {
 +    fn default() -> Self {
 +        Color { r: 0, g: 0, b: 0 }
 +    }
 +}
 +
 +pub struct Color2 {
 +    pub r: u8,
 +    pub g: u8,
 +    pub b: u8,
 +}
 +
 +impl Default for Color2 {
 +    /// `#000000`
 +    fn default() -> Self {
 +        Self { r: 0, g: 0, b: 0 }
 +    }
 +}
 +
++pub struct RepeatDefault1 {
++    a: [i8; 32],
++}
++
++impl Default for RepeatDefault1 {
++    fn default() -> Self {
++        RepeatDefault1 { a: [0; 32] }
++    }
++}
++
++pub struct RepeatDefault2 {
++    a: [i8; 33],
++}
++
++impl Default for RepeatDefault2 {
++    fn default() -> Self {
++        RepeatDefault2 { a: [0; 33] }
++    }
++}
++
++// https://github.com/rust-lang/rust-clippy/issues/7753
++
++pub enum IntOrString {
++    Int(i32),
++    String(String),
++}
++
++impl Default for IntOrString {
++    fn default() -> Self {
++        IntOrString::Int(0)
++    }
++}
++
 +fn main() {}
index 4ed64fade026d1379667ccbff05bb1b7c20038fe,0000000000000000000000000000000000000000..49fb471a21962ce11c69a8b84bccf96a33af3b72
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,89 @@@
- error: aborting due to 6 previous errors
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:18:1
 +   |
 +LL | / impl std::default::Default for FooDefault<'_> {
 +LL | |     fn default() -> Self {
 +LL | |         Self {
 +LL | |             a: false,
 +...  |
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::derivable-impls` implied by `-D warnings`
 +   = help: try annotating `FooDefault` with `#[derive(Default)]`
 +
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:39:1
 +   |
 +LL | / impl std::default::Default for TupleDefault {
 +LL | |     fn default() -> Self {
 +LL | |         Self(false, 0, 0u64)
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: try annotating `TupleDefault` with `#[derive(Default)]`
 +
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:91:1
 +   |
 +LL | / impl Default for StrDefault<'_> {
 +LL | |     fn default() -> Self {
 +LL | |         Self("")
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: try annotating `StrDefault` with `#[derive(Default)]`
 +
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:117:1
 +   |
 +LL | / impl Default for Y {
 +LL | |     fn default() -> Self {
 +LL | |         Self(mac!())
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: try annotating `Y` with `#[derive(Default)]`
 +
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:156:1
 +   |
 +LL | / impl Default for WithoutSelfCurly {
 +LL | |     fn default() -> Self {
 +LL | |         WithoutSelfCurly { a: false }
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: try annotating `WithoutSelfCurly` with `#[derive(Default)]`
 +
 +error: this `impl` can be derived
 +  --> $DIR/derivable_impls.rs:164:1
 +   |
 +LL | / impl Default for WithoutSelfParan {
 +LL | |     fn default() -> Self {
 +LL | |         WithoutSelfParan(false)
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: try annotating `WithoutSelfParan` with `#[derive(Default)]`
 +
++error: this `impl` can be derived
++  --> $DIR/derivable_impls.rs:214:1
++   |
++LL | / impl Default for RepeatDefault1 {
++LL | |     fn default() -> Self {
++LL | |         RepeatDefault1 { a: [0; 32] }
++LL | |     }
++LL | | }
++   | |_^
++   |
++   = help: try annotating `RepeatDefault1` with `#[derive(Default)]`
++
++error: aborting due to 7 previous errors
 +
index 8b0c0f304fce0f8fc318e83f1e8d01dc90e77b1e,0000000000000000000000000000000000000000..342208e52b8e945ea68881260f7186a35d9cfb4a
mode 100644,000000..100644
--- /dev/null
@@@ -1,221 -1,0 +1,226 @@@
 +//! This file tests for the `DOC_MARKDOWN` lint.
 +
 +#![allow(dead_code, incomplete_features)]
 +#![warn(clippy::doc_markdown)]
 +#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
 +#![rustfmt::skip]
 +
 +/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
 +/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
 +/// which should be reported only once despite being __doubly bad__.
 +/// Here be ::a::global:path.
 +/// That's not code ~NotInCodeBlock~.
 +/// be_sure_we_got_to_the_end_of_it
 +fn foo_bar() {
 +}
 +
 +/// That one tests multiline ticks.
 +/// ```rust
 +/// foo_bar FOO_BAR
 +/// _foo bar_
 +/// ```
 +///
 +/// ~~~rust
 +/// foo_bar FOO_BAR
 +/// _foo bar_
 +/// ~~~
 +/// be_sure_we_got_to_the_end_of_it
 +fn multiline_codeblock() {
 +}
 +
 +/// This _is a test for
 +/// multiline
 +/// emphasis_.
 +/// be_sure_we_got_to_the_end_of_it
 +fn test_emphasis() {
 +}
 +
 +/// This tests units. See also #835.
 +/// kiB MiB GiB TiB PiB EiB
 +/// kib Mib Gib Tib Pib Eib
 +/// kB MB GB TB PB EB
 +/// kb Mb Gb Tb Pb Eb
 +/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
 +/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
 +/// 32kB 32MB 32GB 32TB 32PB 32EB
 +/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
 +/// NaN
 +/// be_sure_we_got_to_the_end_of_it
 +fn test_units() {
 +}
 +
 +/// This tests allowed identifiers.
 +/// KiB MiB GiB TiB PiB EiB
 +/// DirectX
 +/// ECMAScript
 +/// GPLv2 GPLv3
 +/// GitHub GitLab
 +/// IPv4 IPv6
 +/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
 +/// NaN NaNs
 +/// OAuth GraphQL
 +/// OCaml
 +/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
 +/// WebGL
 +/// TensorFlow
 +/// TrueType
 +/// iOS macOS FreeBSD
 +/// TeX LaTeX BibTeX BibLaTeX
 +/// MinGW
 +/// CamelCase (see also #2395)
 +/// be_sure_we_got_to_the_end_of_it
 +fn test_allowed() {
 +}
 +
 +/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
 +/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
 +/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
 +/// It can also be [inline_link2].
 +///
 +/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
 +/// [inline_link]: https://foobar
 +/// [inline_link2]: https://foobar
 +/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
 +/// `multiline_ticks` functions.
 +///
 +/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
 +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
 +/// be_sure_we_got_to_the_end_of_it
 +fn main() {
 +    foo_bar();
 +    multiline_codeblock();
 +    test_emphasis();
 +    test_units();
 +}
 +
 +/// ## CamelCaseThing
 +/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
 +///
 +/// # CamelCaseThing
 +///
 +/// Not a title #897 CamelCaseThing
 +/// be_sure_we_got_to_the_end_of_it
 +fn issue897() {
 +}
 +
 +/// I am confused by brackets? (`x_y`)
 +/// I am confused by brackets? (foo `x_y`)
 +/// I am confused by brackets? (`x_y` foo)
 +/// be_sure_we_got_to_the_end_of_it
 +fn issue900() {
 +}
 +
 +/// Diesel queries also have a similar problem to [Iterator][iterator], where
 +/// /// More talking
 +/// returning them from a function requires exposing the implementation of that
 +/// function. The [`helper_types`][helper_types] module exists to help with this,
 +/// but you might want to hide the return type or have it conditionally change.
 +/// Boxing can achieve both.
 +///
 +/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
 +/// [helper_types]: ../helper_types/index.html
 +/// be_sure_we_got_to_the_end_of_it
 +fn issue883() {
 +}
 +
 +/// `foo_bar
 +/// baz_quz`
 +/// [foo
 +/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
 +fn multiline() {
 +}
 +
 +/** E.g., serialization of an empty list: FooBar
 +```
 +That's in a code block: `PackedNode`
 +```
 +
 +And BarQuz too.
 +be_sure_we_got_to_the_end_of_it
 +*/
 +fn issue1073() {
 +}
 +
 +/** E.g., serialization of an empty list: FooBar
 +```
 +That's in a code block: PackedNode
 +```
 +
 +And BarQuz too.
 +be_sure_we_got_to_the_end_of_it
 +*/
 +fn issue1073_alt() {
 +}
 +
 +/// Tests more than three quotes:
 +/// ````
 +/// DoNotWarn
 +/// ```
 +/// StillDont
 +/// ````
 +/// be_sure_we_got_to_the_end_of_it
 +fn four_quotes() {
 +}
 +
 +/// See [NIST SP 800-56A, revision 2].
 +///
 +/// [NIST SP 800-56A, revision 2]:
 +///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
 +fn issue_902_comment() {}
 +
 +#[cfg_attr(feature = "a", doc = " ```")]
 +#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
 +/// fn main() {
 +///     let s = "localhost:10000".to_string();
 +///     println!("{}", s);
 +/// }
 +/// ```
 +fn issue_1469() {}
 +
 +/**
 + * This is a doc comment that should not be a list
 + *This would also be an error under a strict common mark interpretation
 + */
 +fn issue_1920() {}
 +
 +/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
 +///
 +/// Not ok: http://www.unicode.org
 +/// Not ok: https://www.unicode.org
 +/// Not ok: http://www.unicode.org/
 +/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
 +fn issue_1832() {}
 +
 +/// An iterator over mycrate::Collection's values.
 +/// It should not lint a `'static` lifetime in ticks.
 +fn issue_2210() {}
 +
 +/// This should not cause the lint to trigger:
 +/// #REQ-data-family.lint_partof_exists
 +fn issue_2343() {}
 +
 +/// This should not cause an ICE:
 +/// __|_ _|__||_|
 +fn pulldown_cmark_crash() {}
 +
++/// This should not lint
++/// (regression test for #7758)
++/// [plain text][path::to::item]
++fn intra_doc_link() {}
++
 +// issue #7033 - generic_const_exprs ICE
 +struct S<T, const N: usize>
 +where [(); N.checked_next_power_of_two().unwrap()]: {
 +    arr: [T; N.checked_next_power_of_two().unwrap()],
 +    n: usize,
 +}
 +
 +impl<T: Copy + Default, const N: usize> S<T, N>
 +where [(); N.checked_next_power_of_two().unwrap()]: {
 +    fn new() -> Self {
 +        Self {
 +            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
 +            n: 0,
 +        }
 +    }
 +}
index 484aa72d59a25a43c6276ebf4d48dd7ba12e7c01,0000000000000000000000000000000000000000..8f823f1672ba2d30e868414cdf87104a39caa175
mode 100644,000000..100644
--- /dev/null
@@@ -1,100 -1,0 +1,117 @@@
- pub trait UnsafeTrait {
 +// aux-build:doc_unsafe_macros.rs
 +
 +#[macro_use]
 +extern crate doc_unsafe_macros;
 +
 +/// This is not sufficiently documented
 +pub unsafe fn destroy_the_planet() {
 +    unimplemented!();
 +}
 +
 +/// This one is
 +///
 +/// # Safety
 +///
 +/// This function shouldn't be called unless the horsemen are ready
 +pub unsafe fn apocalypse(universe: &mut ()) {
 +    unimplemented!();
 +}
 +
 +/// This is a private function, so docs aren't necessary
 +unsafe fn you_dont_see_me() {
 +    unimplemented!();
 +}
 +
 +mod private_mod {
 +    pub unsafe fn only_crate_wide_accessible() {
 +        unimplemented!();
 +    }
 +
 +    pub unsafe fn republished() {
 +        unimplemented!();
 +    }
 +}
 +
 +pub use private_mod::republished;
 +
- impl UnsafeTrait for Struct {
++pub trait SafeTraitUnsafeMethods {
 +    unsafe fn woefully_underdocumented(self);
 +
 +    /// # Safety
 +    unsafe fn at_least_somewhat_documented(self);
 +}
 +
++pub unsafe trait UnsafeTrait {
++    fn method();
++}
++
++/// # Safety
++pub unsafe trait DocumentedUnsafeTrait {
++    fn method2();
++}
++
 +pub struct Struct;
 +
++impl SafeTraitUnsafeMethods for Struct {
 +    unsafe fn woefully_underdocumented(self) {
 +        // all is well
 +    }
 +
 +    unsafe fn at_least_somewhat_documented(self) {
 +        // all is still well
 +    }
 +}
 +
++unsafe impl UnsafeTrait for Struct {
++    fn method() {}
++}
++
++unsafe impl DocumentedUnsafeTrait for Struct {
++    fn method2() {}
++}
++
 +impl Struct {
 +    pub unsafe fn more_undocumented_unsafe() -> Self {
 +        unimplemented!();
 +    }
 +
 +    /// # Safety
 +    pub unsafe fn somewhat_documented(&self) {
 +        unimplemented!();
 +    }
 +
 +    unsafe fn private(&self) {
 +        unimplemented!();
 +    }
 +}
 +
 +macro_rules! very_unsafe {
 +    () => {
 +        pub unsafe fn whee() {
 +            unimplemented!()
 +        }
 +
 +        /// # Safety
 +        ///
 +        /// Please keep the seat belt fastened
 +        pub unsafe fn drive() {
 +            whee()
 +        }
 +    };
 +}
 +
 +very_unsafe!();
 +
 +// we don't lint code from external macros
 +undocd_unsafe!();
 +
 +fn main() {
 +    unsafe {
 +        you_dont_see_me();
 +        destroy_the_planet();
 +        let mut universe = ();
 +        apocalypse(&mut universe);
 +        private_mod::only_crate_wide_accessible();
 +        drive();
 +    }
 +}
index 73b53f3431e7aa8737be2a2e998aa4ad665d6c73,0000000000000000000000000000000000000000..34ca37a6efdc0197c9b115dd6ccb81980f41557a
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,55 @@@
-   --> $DIR/doc_unsafe.rs:57:5
 +error: unsafe function's docs miss `# Safety` section
 +  --> $DIR/doc_unsafe.rs:7:1
 +   |
 +LL | / pub unsafe fn destroy_the_planet() {
 +LL | |     unimplemented!();
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::missing-safety-doc` implied by `-D warnings`
 +
 +error: unsafe function's docs miss `# Safety` section
 +  --> $DIR/doc_unsafe.rs:30:5
 +   |
 +LL | /     pub unsafe fn republished() {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: unsafe function's docs miss `# Safety` section
 +  --> $DIR/doc_unsafe.rs:38:5
 +   |
 +LL |     unsafe fn woefully_underdocumented(self);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
++error: docs for unsafe trait missing `# Safety` section
++  --> $DIR/doc_unsafe.rs:44:1
++   |
++LL | / pub unsafe trait UnsafeTrait {
++LL | |     fn method();
++LL | | }
++   | |_^
++
 +error: unsafe function's docs miss `# Safety` section
-   --> $DIR/doc_unsafe.rs:73:9
++  --> $DIR/doc_unsafe.rs:74:5
 +   |
 +LL | /     pub unsafe fn more_undocumented_unsafe() -> Self {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: unsafe function's docs miss `# Safety` section
- error: aborting due to 5 previous errors
++  --> $DIR/doc_unsafe.rs:90:9
 +   |
 +LL | /         pub unsafe fn whee() {
 +LL | |             unimplemented!()
 +LL | |         }
 +   | |_________^
 +...
 +LL |   very_unsafe!();
 +   |   --------------- in this macro invocation
 +   |
 +   = note: this error originates in the macro `very_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
++error: aborting due to 6 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ba72cc237b4a58e1b0c51f5470f88273e6f87292
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,69 @@@
++// run-rustfix
++
++#![allow(unused_variables, dead_code)]
++#![warn(clippy::equatable_if_let)]
++
++use std::cmp::Ordering;
++
++#[derive(PartialEq)]
++enum Enum {
++    TupleVariant(i32, u64),
++    RecordVariant { a: i64, b: u32 },
++    UnitVariant,
++    Recursive(Struct),
++}
++
++#[derive(PartialEq)]
++struct Struct {
++    a: i32,
++    b: bool,
++}
++
++enum NotPartialEq {
++    A,
++    B,
++}
++
++enum NotStructuralEq {
++    A,
++    B,
++}
++
++impl PartialEq for NotStructuralEq {
++    fn eq(&self, _: &NotStructuralEq) -> bool {
++        false
++    }
++}
++
++fn main() {
++    let a = 2;
++    let b = 3;
++    let c = Some(2);
++    let d = Struct { a: 2, b: false };
++    let e = Enum::UnitVariant;
++    let f = NotPartialEq::A;
++    let g = NotStructuralEq::A;
++
++    // true
++
++    if a == 2 {}
++    if a.cmp(&b) == Ordering::Greater {}
++    if c == Some(2) {}
++    if d == (Struct { a: 2, b: false }) {}
++    if e == Enum::TupleVariant(32, 64) {}
++    if e == (Enum::RecordVariant { a: 64, b: 32 }) {}
++    if e == Enum::UnitVariant {}
++    if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {}
++
++    // false
++
++    if let 2 | 3 = a {}
++    if let x @ 2 = a {}
++    if let Some(3 | 4) = c {}
++    if let Struct { a, b: false } = d {}
++    if let Struct { a: 2, b: x } = d {}
++    if let NotPartialEq::A = f {}
++    if g == NotStructuralEq::A {}
++    if let Some(NotPartialEq::A) = Some(f) {}
++    if Some(g) == Some(NotStructuralEq::A) {}
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..12526ca193db6b6fd6b1ca3244070a7faa5c9a20
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,69 @@@
++// run-rustfix
++
++#![allow(unused_variables, dead_code)]
++#![warn(clippy::equatable_if_let)]
++
++use std::cmp::Ordering;
++
++#[derive(PartialEq)]
++enum Enum {
++    TupleVariant(i32, u64),
++    RecordVariant { a: i64, b: u32 },
++    UnitVariant,
++    Recursive(Struct),
++}
++
++#[derive(PartialEq)]
++struct Struct {
++    a: i32,
++    b: bool,
++}
++
++enum NotPartialEq {
++    A,
++    B,
++}
++
++enum NotStructuralEq {
++    A,
++    B,
++}
++
++impl PartialEq for NotStructuralEq {
++    fn eq(&self, _: &NotStructuralEq) -> bool {
++        false
++    }
++}
++
++fn main() {
++    let a = 2;
++    let b = 3;
++    let c = Some(2);
++    let d = Struct { a: 2, b: false };
++    let e = Enum::UnitVariant;
++    let f = NotPartialEq::A;
++    let g = NotStructuralEq::A;
++
++    // true
++
++    if let 2 = a {}
++    if let Ordering::Greater = a.cmp(&b) {}
++    if let Some(2) = c {}
++    if let Struct { a: 2, b: false } = d {}
++    if let Enum::TupleVariant(32, 64) = e {}
++    if let Enum::RecordVariant { a: 64, b: 32 } = e {}
++    if let Enum::UnitVariant = e {}
++    if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {}
++
++    // false
++
++    if let 2 | 3 = a {}
++    if let x @ 2 = a {}
++    if let Some(3 | 4) = c {}
++    if let Struct { a, b: false } = d {}
++    if let Struct { a: 2, b: x } = d {}
++    if let NotPartialEq::A = f {}
++    if let NotStructuralEq::A = g {}
++    if let Some(NotPartialEq::A) = Some(f) {}
++    if let Some(NotStructuralEq::A) = Some(g) {}
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..79ef919384df28abc1032e096565ade0147f3d79
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,64 @@@
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:49:8
++   |
++LL |     if let 2 = a {}
++   |        ^^^^^^^^^ help: try: `a == 2`
++   |
++   = note: `-D clippy::equatable-if-let` implied by `-D warnings`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:50:8
++   |
++LL |     if let Ordering::Greater = a.cmp(&b) {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:51:8
++   |
++LL |     if let Some(2) = c {}
++   |        ^^^^^^^^^^^^^^^ help: try: `c == Some(2)`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:52:8
++   |
++LL |     if let Struct { a: 2, b: false } = d {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:53:8
++   |
++LL |     if let Enum::TupleVariant(32, 64) = e {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:54:8
++   |
++LL |     if let Enum::RecordVariant { a: 64, b: 32 } = e {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:55:8
++   |
++LL |     if let Enum::UnitVariant = e {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:56:8
++   |
++LL |     if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:66:8
++   |
++LL |     if let NotStructuralEq::A = g {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A`
++
++error: this pattern matching can be expressed using equality
++  --> $DIR/equatable_if_let.rs:68:8
++   |
++LL |     if let Some(NotStructuralEq::A) = Some(g) {}
++   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
++
++error: aborting due to 10 previous errors
++
index 90376620a9fd835d867fbe9b7bdc8538321628cc,0000000000000000000000000000000000000000..b74bda182be9bbe10a41c497a2c7ba9e356948fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,69 @@@
 +// run-rustfix
 +#![warn(clippy::excessive_precision)]
 +#![allow(dead_code, unused_variables, clippy::print_literal)]
 +
 +fn main() {
 +    // Consts
 +    const GOOD32: f32 = 0.123_456;
 +    const GOOD32_SM: f32 = 0.000_000_000_1;
 +    const GOOD32_DOT: f32 = 10_000_000_000.0;
 +    const GOOD32_EDGE: f32 = 1.000_000_8;
 +    const GOOD64: f64 = 0.123_456_789_012;
 +    const GOOD64_SM: f32 = 0.000_000_000_000_000_1;
 +    const GOOD64_DOT: f32 = 10_000_000_000_000_000.0;
 +
 +    const BAD32_1: f32 = 0.123_456_79_f32;
 +    const BAD32_2: f32 = 0.123_456_79;
 +    const BAD32_3: f32 = 0.1;
 +    const BAD32_EDGE: f32 = 1.000_001;
 +
 +    const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
 +    const BAD64_2: f64 = 0.123_456_789_012_345_67;
 +    const BAD64_3: f64 = 0.1;
 +
 +    // Literal as param
 +    println!("{:?}", 8.888_888_888_888_89);
 +
 +    // // TODO add inferred type tests for f32
 +    // Locals
 +    let good32: f32 = 0.123_456_f32;
 +    let good32_2: f32 = 0.123_456;
 +
 +    let good64: f64 = 0.123_456_789_012;
 +    let good64_suf: f64 = 0.123_456_789_012f64;
 +    let good64_inf = 0.123_456_789_012;
 +
 +    let bad32: f32 = 1.123_456_8;
 +    let bad32_suf: f32 = 1.123_456_8_f32;
 +    let bad32_inf = 1.123_456_8_f32;
 +
 +    let bad64: f64 = 0.123_456_789_012_345_67;
 +    let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
 +    let bad64_inf = 0.123_456_789_012_345_67;
 +
 +    // Vectors
 +    let good_vec32: Vec<f32> = vec![0.123_456];
 +    let good_vec64: Vec<f64> = vec![0.123_456_789];
 +
 +    let bad_vec32: Vec<f32> = vec![0.123_456_79];
 +    let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
 +
 +    // Exponential float notation
 +    let good_e32: f32 = 1e-10;
 +    let bad_e32: f32 = 1.123_456_8e-10;
 +
 +    let good_bige32: f32 = 1E-10;
 +    let bad_bige32: f32 = 1.123_456_8E-10;
 +
 +    // Inferred type
 +    let good_inferred: f32 = 1f32 * 1_000_000_000.;
 +
 +    // issue #2840
 +    let num = 0.000_000_000_01e-10f64;
++
++    // issue #7744
++    let _ = 2.225_073_858_507_201e-308_f64;
++
++    // issue #7745
++    let _ = 0_f64;
 +}
index ce4722a90f9002edd571d1d2123861905f5726c3,0000000000000000000000000000000000000000..6e84a71f24cb6a504d5f514143c94dea4fa4aac9
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,69 @@@
 +// run-rustfix
 +#![warn(clippy::excessive_precision)]
 +#![allow(dead_code, unused_variables, clippy::print_literal)]
 +
 +fn main() {
 +    // Consts
 +    const GOOD32: f32 = 0.123_456;
 +    const GOOD32_SM: f32 = 0.000_000_000_1;
 +    const GOOD32_DOT: f32 = 10_000_000_000.0;
 +    const GOOD32_EDGE: f32 = 1.000_000_8;
 +    const GOOD64: f64 = 0.123_456_789_012;
 +    const GOOD64_SM: f32 = 0.000_000_000_000_000_1;
 +    const GOOD64_DOT: f32 = 10_000_000_000_000_000.0;
 +
 +    const BAD32_1: f32 = 0.123_456_789_f32;
 +    const BAD32_2: f32 = 0.123_456_789;
 +    const BAD32_3: f32 = 0.100_000_000_000_1;
 +    const BAD32_EDGE: f32 = 1.000_000_9;
 +
 +    const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
 +    const BAD64_2: f64 = 0.123_456_789_012_345_67;
 +    const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
 +
 +    // Literal as param
 +    println!("{:?}", 8.888_888_888_888_888_888_888);
 +
 +    // // TODO add inferred type tests for f32
 +    // Locals
 +    let good32: f32 = 0.123_456_f32;
 +    let good32_2: f32 = 0.123_456;
 +
 +    let good64: f64 = 0.123_456_789_012;
 +    let good64_suf: f64 = 0.123_456_789_012f64;
 +    let good64_inf = 0.123_456_789_012;
 +
 +    let bad32: f32 = 1.123_456_789;
 +    let bad32_suf: f32 = 1.123_456_789_f32;
 +    let bad32_inf = 1.123_456_789_f32;
 +
 +    let bad64: f64 = 0.123_456_789_012_345_67;
 +    let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
 +    let bad64_inf = 0.123_456_789_012_345_67;
 +
 +    // Vectors
 +    let good_vec32: Vec<f32> = vec![0.123_456];
 +    let good_vec64: Vec<f64> = vec![0.123_456_789];
 +
 +    let bad_vec32: Vec<f32> = vec![0.123_456_789];
 +    let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
 +
 +    // Exponential float notation
 +    let good_e32: f32 = 1e-10;
 +    let bad_e32: f32 = 1.123_456_788_888e-10;
 +
 +    let good_bige32: f32 = 1E-10;
 +    let bad_bige32: f32 = 1.123_456_788_888E-10;
 +
 +    // Inferred type
 +    let good_inferred: f32 = 1f32 * 1_000_000_000.;
 +
 +    // issue #2840
 +    let num = 0.000_000_000_01e-10f64;
++
++    // issue #7744
++    let _ = 2.225_073_858_507_201_1e-308_f64;
++
++    // issue #7745
++    let _ = 1.000_000_000_000_001e-324_f64;
 +}
index e59c20c30b4fda7bbfcceb15b60f2ceff69d9cb4,0000000000000000000000000000000000000000..42d9d4de193c40c5edcba90e479d3e8ffa96e04f
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,94 @@@
- error: aborting due to 13 previous errors
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:15:26
 +   |
 +LL |     const BAD32_1: f32 = 0.123_456_789_f32;
 +   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32`
 +   |
 +   = note: `-D clippy::excessive-precision` implied by `-D warnings`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:16:26
 +   |
 +LL |     const BAD32_2: f32 = 0.123_456_789;
 +   |                          ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:17:26
 +   |
 +LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
 +   |                          ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:18:29
 +   |
 +LL |     const BAD32_EDGE: f32 = 1.000_000_9;
 +   |                             ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:22:26
 +   |
 +LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
 +   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:25:22
 +   |
 +LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:36:22
 +   |
 +LL |     let bad32: f32 = 1.123_456_789;
 +   |                      ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:37:26
 +   |
 +LL |     let bad32_suf: f32 = 1.123_456_789_f32;
 +   |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:38:21
 +   |
 +LL |     let bad32_inf = 1.123_456_789_f32;
 +   |                     ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:48:36
 +   |
 +LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
 +   |                                    ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:49:36
 +   |
 +LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
 +   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:53:24
 +   |
 +LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
 +   |                        ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10`
 +
 +error: float has excessive precision
 +  --> $DIR/excessive_precision.rs:56:27
 +   |
 +LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
 +   |                           ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
 +
++error: float has excessive precision
++  --> $DIR/excessive_precision.rs:65:13
++   |
++LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64`
++
++error: float has excessive precision
++  --> $DIR/excessive_precision.rs:68:13
++   |
++LL |     let _ = 1.000_000_000_000_001e-324_f64;
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64`
++
++error: aborting due to 15 previous errors
 +
index f0e4835415f306411b1a6d97049e9abc361194af,0000000000000000000000000000000000000000..f373e905d05cad19c78608b6dd8008db6d4224e2
mode 100644,000000..100644
--- /dev/null
@@@ -1,309 -1,0 +1,304 @@@
- #[allow(
-     clippy::linkedlist,
-     clippy::shadow_unrelated,
-     clippy::unnecessary_mut_passed,
-     clippy::similar_names
- )]
 +// run-rustfix
 +
 +#![allow(dead_code, unused)]
 +
 +use std::collections::*;
 +
 +#[warn(clippy::all)]
 +struct Unrelated(Vec<u8>);
 +impl Unrelated {
 +    fn next(&self) -> std::slice::Iter<u8> {
 +        self.0.iter()
 +    }
 +
 +    fn iter(&self) -> std::slice::Iter<u8> {
 +        self.0.iter()
 +    }
 +}
 +
 +#[warn(
 +    clippy::needless_range_loop,
 +    clippy::explicit_iter_loop,
 +    clippy::explicit_into_iter_loop,
 +    clippy::iter_next_loop,
 +    clippy::for_kv_map
 +)]
++#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
 +#[allow(unused_variables)]
 +fn main() {
 +    let mut vec = vec![1, 2, 3, 4];
 +
 +    // See #601
 +    for i in 0..10 {
 +        // no error, id_col does not exist outside the loop
 +        let mut id_col = vec![0f64; 10];
 +        id_col[i] = 1f64;
 +    }
 +
 +    for _v in &vec {}
 +
 +    for _v in &mut vec {}
 +
 +    let out_vec = vec![1, 2, 3];
 +    for _v in out_vec {}
 +
 +    for _v in &vec {} // these are fine
 +    for _v in &mut vec {} // these are fine
 +
 +    for _v in &[1, 2, 3] {}
 +
 +    for _v in (&mut [1, 2, 3]).iter() {} // no error
 +
 +    for _v in &[0; 32] {}
 +
 +    for _v in [0; 33].iter() {} // no error
 +
 +    let ll: LinkedList<()> = LinkedList::new();
 +    for _v in &ll {}
 +
 +    let vd: VecDeque<()> = VecDeque::new();
 +    for _v in &vd {}
 +
 +    let bh: BinaryHeap<()> = BinaryHeap::new();
 +    for _v in &bh {}
 +
 +    let hm: HashMap<(), ()> = HashMap::new();
 +    for _v in &hm {}
 +
 +    let bt: BTreeMap<(), ()> = BTreeMap::new();
 +    for _v in &bt {}
 +
 +    let hs: HashSet<()> = HashSet::new();
 +    for _v in &hs {}
 +
 +    let bs: BTreeSet<()> = BTreeSet::new();
 +    for _v in &bs {}
 +
 +    let u = Unrelated(vec![]);
 +    for _v in u.next() {} // no error
 +    for _v in u.iter() {} // no error
 +
 +    let mut out = vec![];
 +    vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
 +    let _y = vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine
 +
 +    // Loop with explicit counter variable
 +
 +    // Potential false positives
 +    let mut _index = 0;
 +    _index = 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    _index += 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    if true {
 +        _index = 1
 +    }
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    let mut _index = 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index += 1;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index *= 2;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index = 1;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +
 +    for _v in &vec {
 +        let mut _index = 0;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index += 1;
 +        _index = 0;
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        for _x in 0..1 {
 +            _index += 1;
 +        }
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for x in &vec {
 +        if *x == 1 {
 +            _index += 1
 +        }
 +    }
 +
 +    let mut _index = 0;
 +    if true {
 +        _index = 1
 +    };
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 1;
 +    if false {
 +        _index = 0
 +    };
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut index = 0;
 +    {
 +        let mut _x = &mut index;
 +    }
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut index = 0;
 +    for _v in &vec {
 +        index += 1
 +    }
 +    println!("index: {}", index);
 +
 +    fn f<T>(_: &T, _: &T) -> bool {
 +        unimplemented!()
 +    }
 +    fn g<T>(_: &mut [T], _: usize, _: usize) {
 +        unimplemented!()
 +    }
 +    for i in 1..vec.len() {
 +        if f(&vec[i - 1], &vec[i]) {
 +            g(&mut vec, i - 1, i);
 +        }
 +    }
 +
 +    for mid in 1..vec.len() {
 +        let (_, _) = vec.split_at(mid);
 +    }
 +}
 +
 +fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
 +    let pivot = v.len() - 1;
 +    let mut i = 0;
 +    for j in 0..pivot {
 +        if v[j] <= v[pivot] {
 +            v.swap(i, j);
 +            i += 1;
 +        }
 +    }
 +    v.swap(i, pivot);
 +    i
 +}
 +
 +#[warn(clippy::needless_range_loop)]
 +pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) {
 +    // Same source and destination - don't trigger lint
 +    for i in 0..dst.len() {
 +        dst[d + i] = dst[s + i];
 +    }
 +}
 +
 +mod issue_2496 {
 +    pub trait Handle {
 +        fn new_for_index(index: usize) -> Self;
 +        fn index(&self) -> usize;
 +    }
 +
 +    pub fn test<H: Handle>() -> H {
 +        for x in 0..5 {
 +            let next_handle = H::new_for_index(x);
 +            println!("{}", next_handle.index());
 +        }
 +        unimplemented!()
 +    }
 +}
 +
 +// explicit_into_iter_loop bad suggestions
 +#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)]
 +mod issue_4958 {
 +    fn takes_iterator<T>(iterator: &T)
 +    where
 +        for<'a> &'a T: IntoIterator<Item = &'a String>,
 +    {
 +        for i in iterator {
 +            println!("{}", i);
 +        }
 +    }
 +
 +    struct T;
 +    impl IntoIterator for &T {
 +        type Item = ();
 +        type IntoIter = std::vec::IntoIter<Self::Item>;
 +        fn into_iter(self) -> Self::IntoIter {
 +            vec![].into_iter()
 +        }
 +    }
 +
 +    fn more_tests() {
 +        let t = T;
 +        let r = &t;
 +        let rr = &&t;
 +
 +        // This case is handled by `explicit_iter_loop`. No idea why.
 +        for _ in &t {}
 +
 +        for _ in r {}
 +
 +        // No suggestion for this.
 +        // We'd have to suggest `for _ in *rr {}` which is less clear.
 +        for _ in rr.into_iter() {}
 +    }
 +}
 +
 +// explicit_into_iter_loop
 +#[warn(clippy::explicit_into_iter_loop)]
 +mod issue_6900 {
 +    struct S;
 +    impl S {
 +        #[allow(clippy::should_implement_trait)]
 +        pub fn into_iter<T>(self) -> I<T> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    struct I<T>(T);
 +    impl<T> Iterator for I<T> {
 +        type Item = T;
 +        fn next(&mut self) -> Option<Self::Item> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    fn f() {
 +        for _ in S.into_iter::<u32>() {
 +            unimplemented!()
 +        }
 +    }
 +}
index 1edef175fb9833e297a91c5c7d550e2884e57e49,0000000000000000000000000000000000000000..3814583bb6ef42d51f9732372d1fb11d2ded5ebb
mode 100644,000000..100644
--- /dev/null
@@@ -1,309 -1,0 +1,304 @@@
- #[allow(
-     clippy::linkedlist,
-     clippy::shadow_unrelated,
-     clippy::unnecessary_mut_passed,
-     clippy::similar_names
- )]
 +// run-rustfix
 +
 +#![allow(dead_code, unused)]
 +
 +use std::collections::*;
 +
 +#[warn(clippy::all)]
 +struct Unrelated(Vec<u8>);
 +impl Unrelated {
 +    fn next(&self) -> std::slice::Iter<u8> {
 +        self.0.iter()
 +    }
 +
 +    fn iter(&self) -> std::slice::Iter<u8> {
 +        self.0.iter()
 +    }
 +}
 +
 +#[warn(
 +    clippy::needless_range_loop,
 +    clippy::explicit_iter_loop,
 +    clippy::explicit_into_iter_loop,
 +    clippy::iter_next_loop,
 +    clippy::for_kv_map
 +)]
++#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
 +#[allow(unused_variables)]
 +fn main() {
 +    let mut vec = vec![1, 2, 3, 4];
 +
 +    // See #601
 +    for i in 0..10 {
 +        // no error, id_col does not exist outside the loop
 +        let mut id_col = vec![0f64; 10];
 +        id_col[i] = 1f64;
 +    }
 +
 +    for _v in vec.iter() {}
 +
 +    for _v in vec.iter_mut() {}
 +
 +    let out_vec = vec![1, 2, 3];
 +    for _v in out_vec.into_iter() {}
 +
 +    for _v in &vec {} // these are fine
 +    for _v in &mut vec {} // these are fine
 +
 +    for _v in [1, 2, 3].iter() {}
 +
 +    for _v in (&mut [1, 2, 3]).iter() {} // no error
 +
 +    for _v in [0; 32].iter() {}
 +
 +    for _v in [0; 33].iter() {} // no error
 +
 +    let ll: LinkedList<()> = LinkedList::new();
 +    for _v in ll.iter() {}
 +
 +    let vd: VecDeque<()> = VecDeque::new();
 +    for _v in vd.iter() {}
 +
 +    let bh: BinaryHeap<()> = BinaryHeap::new();
 +    for _v in bh.iter() {}
 +
 +    let hm: HashMap<(), ()> = HashMap::new();
 +    for _v in hm.iter() {}
 +
 +    let bt: BTreeMap<(), ()> = BTreeMap::new();
 +    for _v in bt.iter() {}
 +
 +    let hs: HashSet<()> = HashSet::new();
 +    for _v in hs.iter() {}
 +
 +    let bs: BTreeSet<()> = BTreeSet::new();
 +    for _v in bs.iter() {}
 +
 +    let u = Unrelated(vec![]);
 +    for _v in u.next() {} // no error
 +    for _v in u.iter() {} // no error
 +
 +    let mut out = vec![];
 +    vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
 +    let _y = vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine
 +
 +    // Loop with explicit counter variable
 +
 +    // Potential false positives
 +    let mut _index = 0;
 +    _index = 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    _index += 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    if true {
 +        _index = 1
 +    }
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    let mut _index = 1;
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index += 1;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index *= 2;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index = 1;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +
 +    for _v in &vec {
 +        let mut _index = 0;
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        _index += 1;
 +        _index = 0;
 +    }
 +
 +    let mut _index = 0;
 +    for _v in &vec {
 +        for _x in 0..1 {
 +            _index += 1;
 +        }
 +        _index += 1
 +    }
 +
 +    let mut _index = 0;
 +    for x in &vec {
 +        if *x == 1 {
 +            _index += 1
 +        }
 +    }
 +
 +    let mut _index = 0;
 +    if true {
 +        _index = 1
 +    };
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut _index = 1;
 +    if false {
 +        _index = 0
 +    };
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut index = 0;
 +    {
 +        let mut _x = &mut index;
 +    }
 +    for _v in &vec {
 +        _index += 1
 +    }
 +
 +    let mut index = 0;
 +    for _v in &vec {
 +        index += 1
 +    }
 +    println!("index: {}", index);
 +
 +    fn f<T>(_: &T, _: &T) -> bool {
 +        unimplemented!()
 +    }
 +    fn g<T>(_: &mut [T], _: usize, _: usize) {
 +        unimplemented!()
 +    }
 +    for i in 1..vec.len() {
 +        if f(&vec[i - 1], &vec[i]) {
 +            g(&mut vec, i - 1, i);
 +        }
 +    }
 +
 +    for mid in 1..vec.len() {
 +        let (_, _) = vec.split_at(mid);
 +    }
 +}
 +
 +fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
 +    let pivot = v.len() - 1;
 +    let mut i = 0;
 +    for j in 0..pivot {
 +        if v[j] <= v[pivot] {
 +            v.swap(i, j);
 +            i += 1;
 +        }
 +    }
 +    v.swap(i, pivot);
 +    i
 +}
 +
 +#[warn(clippy::needless_range_loop)]
 +pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) {
 +    // Same source and destination - don't trigger lint
 +    for i in 0..dst.len() {
 +        dst[d + i] = dst[s + i];
 +    }
 +}
 +
 +mod issue_2496 {
 +    pub trait Handle {
 +        fn new_for_index(index: usize) -> Self;
 +        fn index(&self) -> usize;
 +    }
 +
 +    pub fn test<H: Handle>() -> H {
 +        for x in 0..5 {
 +            let next_handle = H::new_for_index(x);
 +            println!("{}", next_handle.index());
 +        }
 +        unimplemented!()
 +    }
 +}
 +
 +// explicit_into_iter_loop bad suggestions
 +#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)]
 +mod issue_4958 {
 +    fn takes_iterator<T>(iterator: &T)
 +    where
 +        for<'a> &'a T: IntoIterator<Item = &'a String>,
 +    {
 +        for i in iterator.into_iter() {
 +            println!("{}", i);
 +        }
 +    }
 +
 +    struct T;
 +    impl IntoIterator for &T {
 +        type Item = ();
 +        type IntoIter = std::vec::IntoIter<Self::Item>;
 +        fn into_iter(self) -> Self::IntoIter {
 +            vec![].into_iter()
 +        }
 +    }
 +
 +    fn more_tests() {
 +        let t = T;
 +        let r = &t;
 +        let rr = &&t;
 +
 +        // This case is handled by `explicit_iter_loop`. No idea why.
 +        for _ in t.into_iter() {}
 +
 +        for _ in r.into_iter() {}
 +
 +        // No suggestion for this.
 +        // We'd have to suggest `for _ in *rr {}` which is less clear.
 +        for _ in rr.into_iter() {}
 +    }
 +}
 +
 +// explicit_into_iter_loop
 +#[warn(clippy::explicit_into_iter_loop)]
 +mod issue_6900 {
 +    struct S;
 +    impl S {
 +        #[allow(clippy::should_implement_trait)]
 +        pub fn into_iter<T>(self) -> I<T> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    struct I<T>(T);
 +    impl<T> Iterator for I<T> {
 +        type Item = T;
 +        fn next(&mut self) -> Option<Self::Item> {
 +            unimplemented!()
 +        }
 +    }
 +
 +    fn f() {
 +        for _ in S.into_iter::<u32>() {
 +            unimplemented!()
 +        }
 +    }
 +}
index ddfe66d675f91efbc8f070116c570ef9eda5a496,0000000000000000000000000000000000000000..009dbe1a0bfaf49f2a967696b471e5e4b541475e
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,96 @@@
-   --> $DIR/for_loop_fixable.rs:43:15
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:45:15
++  --> $DIR/for_loop_fixable.rs:38:15
 +   |
 +LL |     for _v in vec.iter() {}
 +   |               ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
 +   |
 +   = note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:48:15
++  --> $DIR/for_loop_fixable.rs:40:15
 +   |
 +LL |     for _v in vec.iter_mut() {}
 +   |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
 +
 +error: it is more concise to loop over containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:53:15
++  --> $DIR/for_loop_fixable.rs:43:15
 +   |
 +LL |     for _v in out_vec.into_iter() {}
 +   |               ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
 +   |
 +   = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:57:15
++  --> $DIR/for_loop_fixable.rs:48:15
 +   |
 +LL |     for _v in [1, 2, 3].iter() {}
 +   |               ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:62:15
++  --> $DIR/for_loop_fixable.rs:52:15
 +   |
 +LL |     for _v in [0; 32].iter() {}
 +   |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:65:15
++  --> $DIR/for_loop_fixable.rs:57:15
 +   |
 +LL |     for _v in ll.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&ll`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:68:15
++  --> $DIR/for_loop_fixable.rs:60:15
 +   |
 +LL |     for _v in vd.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&vd`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:71:15
++  --> $DIR/for_loop_fixable.rs:63:15
 +   |
 +LL |     for _v in bh.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&bh`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:74:15
++  --> $DIR/for_loop_fixable.rs:66:15
 +   |
 +LL |     for _v in hm.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&hm`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:77:15
++  --> $DIR/for_loop_fixable.rs:69:15
 +   |
 +LL |     for _v in bt.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&bt`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:80:15
++  --> $DIR/for_loop_fixable.rs:72:15
 +   |
 +LL |     for _v in hs.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&hs`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:255:18
++  --> $DIR/for_loop_fixable.rs:75:15
 +   |
 +LL |     for _v in bs.iter() {}
 +   |               ^^^^^^^^^ help: to write this more concisely, try: `&bs`
 +
 +error: it is more concise to loop over containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:275:18
++  --> $DIR/for_loop_fixable.rs:250:18
 +   |
 +LL |         for i in iterator.into_iter() {
 +   |                  ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator`
 +
 +error: it is more concise to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop_fixable.rs:277:18
++  --> $DIR/for_loop_fixable.rs:270:18
 +   |
 +LL |         for _ in t.into_iter() {}
 +   |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t`
 +
 +error: it is more concise to loop over containers instead of using explicit iteration methods
++  --> $DIR/for_loop_fixable.rs:272:18
 +   |
 +LL |         for _ in r.into_iter() {}
 +   |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `r`
 +
 +error: aborting due to 15 previous errors
 +
index e73536052f0f5bf597dd9154b4209984d87c54a7,0000000000000000000000000000000000000000..efcaffce24ea4d3fc3689d943bde12d444a7644c
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,15 @@@
- #[allow(
-     clippy::linkedlist,
-     clippy::shadow_unrelated,
-     clippy::unnecessary_mut_passed,
-     clippy::similar_names,
-     unused,
-     dead_code
- )]
 +// Tests from for_loop.rs that don't have suggestions
 +
 +#[warn(
 +    clippy::needless_range_loop,
 +    clippy::explicit_iter_loop,
 +    clippy::explicit_into_iter_loop,
 +    clippy::iter_next_loop,
 +    clippy::for_kv_map
 +)]
++#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
 +fn main() {
 +    let vec = vec![1, 2, 3, 4];
 +
 +    for _v in vec.iter().next() {}
 +}
index 1c9287b6acbb328d5b2335a797acb4a1c903a478,0000000000000000000000000000000000000000..f769b4bdc941180c2a5587924192016138f2458a
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,10 @@@
-   --> $DIR/for_loop_unfixable.rs:21:15
 +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
++  --> $DIR/for_loop_unfixable.rs:14:15
 +   |
 +LL |     for _v in vec.iter().next() {}
 +   |               ^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::iter-next-loop` implied by `-D warnings`
 +
 +error: aborting due to previous error
 +
index e4dc5b647dfd2eb0d3a42be5d5e7c262eaf41228,0000000000000000000000000000000000000000..69189d9e0c00d911637b320ba9e48b83e3716124
mode 100644,000000..100644
--- /dev/null
@@@ -1,142 -1,0 +1,143 @@@
 +#![warn(clippy::if_same_then_else)]
 +#![allow(
 +    clippy::blacklisted_name,
 +    clippy::collapsible_else_if,
++    clippy::equatable_if_let,
 +    clippy::collapsible_if,
 +    clippy::ifs_same_cond,
 +    clippy::needless_return,
 +    clippy::single_element_loop,
 +    clippy::branches_sharing_code
 +)]
 +
 +fn if_same_then_else2() -> Result<&'static str, ()> {
 +    if true {
 +        for _ in &[42] {
 +            let foo: &Option<_> = &Some::<u8>(42);
 +            if foo.is_some() {
 +                break;
 +            } else {
 +                continue;
 +            }
 +        }
 +    } else {
 +        //~ ERROR same body as `if` block
 +        for _ in &[42] {
 +            let bar: &Option<_> = &Some::<u8>(42);
 +            if bar.is_some() {
 +                break;
 +            } else {
 +                continue;
 +            }
 +        }
 +    }
 +
 +    if true {
 +        if let Some(a) = Some(42) {}
 +    } else {
 +        //~ ERROR same body as `if` block
 +        if let Some(a) = Some(42) {}
 +    }
 +
 +    if true {
 +        if let (1, .., 3) = (1, 2, 3) {}
 +    } else {
 +        //~ ERROR same body as `if` block
 +        if let (1, .., 3) = (1, 2, 3) {}
 +    }
 +
 +    if true {
 +        if let (1, .., 3) = (1, 2, 3) {}
 +    } else {
 +        if let (.., 3) = (1, 2, 3) {}
 +    }
 +
 +    if true {
 +        if let (1, .., 3) = (1, 2, 3) {}
 +    } else {
 +        if let (.., 4) = (1, 2, 3) {}
 +    }
 +
 +    if true {
 +        if let (1, .., 3) = (1, 2, 3) {}
 +    } else {
 +        if let (.., 1, 3) = (1, 2, 3) {}
 +    }
 +
 +    if true {
 +        if let Some(42) = None {}
 +    } else {
 +        if let Option::Some(42) = None {}
 +    }
 +
 +    if true {
 +        if let Some(42) = None::<u8> {}
 +    } else {
 +        if let Some(42) = None {}
 +    }
 +
 +    if true {
 +        if let Some(42) = None::<u8> {}
 +    } else {
 +        if let Some(42) = None::<u32> {}
 +    }
 +
 +    if true {
 +        if let Some(a) = Some(42) {}
 +    } else {
 +        if let Some(a) = Some(43) {}
 +    }
 +
 +    // Same NaNs
 +    let _ = if true {
 +        f32::NAN
 +    } else {
 +        //~ ERROR same body as `if` block
 +        f32::NAN
 +    };
 +
 +    if true {
 +        Ok("foo")?;
 +    } else {
 +        //~ ERROR same body as `if` block
 +        Ok("foo")?;
 +    }
 +
 +    if true {
 +        let foo = "";
 +        return Ok(&foo[0..]);
 +    } else if false {
 +        let foo = "bar";
 +        return Ok(&foo[0..]);
 +    } else {
 +        let foo = "";
 +        return Ok(&foo[0..]);
 +    }
 +
 +    if true {
 +        let foo = "";
 +        return Ok(&foo[0..]);
 +    } else if false {
 +        let foo = "bar";
 +        return Ok(&foo[0..]);
 +    } else if true {
 +        let foo = "";
 +        return Ok(&foo[0..]);
 +    } else {
 +        let foo = "";
 +        return Ok(&foo[0..]);
 +    }
 +
 +    // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559.
 +    if true {
 +        let foo = "";
 +        let (x, y) = (1, 2);
 +        return Ok(&foo[x..y]);
 +    } else {
 +        let foo = "";
 +        let (y, x) = (1, 2);
 +        return Ok(&foo[x..y]);
 +    }
 +}
 +
 +fn main() {}
index 6524be0af8517ff4925a7723b8554ffd30e7aa93,0000000000000000000000000000000000000000..cac788f859d1e0817dcf231b4fe0ead07896054f
mode 100644,000000..100644
--- /dev/null
@@@ -1,125 -1,0 +1,125 @@@
-   --> $DIR/if_same_then_else2.rs:13:13
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:22:12
++  --> $DIR/if_same_then_else2.rs:14:13
 +   |
 +LL |       if true {
 +   |  _____________^
 +LL | |         for _ in &[42] {
 +LL | |             let foo: &Option<_> = &Some::<u8>(42);
 +LL | |             if foo.is_some() {
 +...  |
 +LL | |         }
 +LL | |     } else {
 +   | |_____^
 +   |
 +   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
 +note: same as this
-   --> $DIR/if_same_then_else2.rs:34:13
++  --> $DIR/if_same_then_else2.rs:23:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         //~ ERROR same body as `if` block
 +LL | |         for _ in &[42] {
 +LL | |             let bar: &Option<_> = &Some::<u8>(42);
 +...  |
 +LL | |         }
 +LL | |     }
 +   | |_____^
 +
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:36:12
++  --> $DIR/if_same_then_else2.rs:35:13
 +   |
 +LL |       if true {
 +   |  _____________^
 +LL | |         if let Some(a) = Some(42) {}
 +LL | |     } else {
 +   | |_____^
 +   |
 +note: same as this
-   --> $DIR/if_same_then_else2.rs:41:13
++  --> $DIR/if_same_then_else2.rs:37:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         //~ ERROR same body as `if` block
 +LL | |         if let Some(a) = Some(42) {}
 +LL | |     }
 +   | |_____^
 +
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:43:12
++  --> $DIR/if_same_then_else2.rs:42:13
 +   |
 +LL |       if true {
 +   |  _____________^
 +LL | |         if let (1, .., 3) = (1, 2, 3) {}
 +LL | |     } else {
 +   | |_____^
 +   |
 +note: same as this
-   --> $DIR/if_same_then_else2.rs:91:21
++  --> $DIR/if_same_then_else2.rs:44:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         //~ ERROR same body as `if` block
 +LL | |         if let (1, .., 3) = (1, 2, 3) {}
 +LL | |     }
 +   | |_____^
 +
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:93:12
++  --> $DIR/if_same_then_else2.rs:92:21
 +   |
 +LL |       let _ = if true {
 +   |  _____________________^
 +LL | |         f32::NAN
 +LL | |     } else {
 +   | |_____^
 +   |
 +note: same as this
-   --> $DIR/if_same_then_else2.rs:98:13
++  --> $DIR/if_same_then_else2.rs:94:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         //~ ERROR same body as `if` block
 +LL | |         f32::NAN
 +LL | |     };
 +   | |_____^
 +
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:100:12
++  --> $DIR/if_same_then_else2.rs:99:13
 +   |
 +LL |       if true {
 +   |  _____________^
 +LL | |         Ok("foo")?;
 +LL | |     } else {
 +   | |_____^
 +   |
 +note: same as this
-   --> $DIR/if_same_then_else2.rs:122:20
++  --> $DIR/if_same_then_else2.rs:101:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         //~ ERROR same body as `if` block
 +LL | |         Ok("foo")?;
 +LL | |     }
 +   | |_____^
 +
 +error: this `if` has identical blocks
-   --> $DIR/if_same_then_else2.rs:125:12
++  --> $DIR/if_same_then_else2.rs:123:20
 +   |
 +LL |       } else if true {
 +   |  ____________________^
 +LL | |         let foo = "";
 +LL | |         return Ok(&foo[0..]);
 +LL | |     } else {
 +   | |_____^
 +   |
 +note: same as this
++  --> $DIR/if_same_then_else2.rs:126:12
 +   |
 +LL |       } else {
 +   |  ____________^
 +LL | |         let foo = "";
 +LL | |         return Ok(&foo[0..]);
 +LL | |     }
 +   | |_____^
 +
 +error: aborting due to 6 previous errors
 +
index fc57ae0dfa5ee0a50a919966ebff18bcc03878ad,0000000000000000000000000000000000000000..0998f8ffa9de4ecf8fe15e4c8e74ed6bdbb3176c
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,40 @@@
 +// run-rustfix
 +#![warn(clippy::if_then_panic)]
 +
 +fn main() {
 +    let a = vec![1, 2, 3];
 +    let c = Some(2);
 +    if !a.is_empty()
 +        && a.len() == 3
 +        && c != None
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +    {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    assert!(a.is_empty(), "qaqaq{:?}", a);
 +    assert!(a.is_empty(), "qwqwq");
 +    if a.len() == 3 {
 +        println!("qwq");
 +        println!("qwq");
 +        println!("qwq");
 +    }
 +    if let Some(b) = c {
 +        panic!("orz {}", b);
 +    }
 +    if a.len() == 3 {
 +        panic!("qaqaq");
 +    } else {
 +        println!("qwq");
 +    }
++    let b = vec![1, 2, 3];
++    assert!(!b.is_empty(), "panic1");
++    assert!(!(b.is_empty() && a.is_empty()), "panic2");
++    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
++    assert!(!(b.is_empty() || a.is_empty()), "panic4");
++    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
 +}
index d1ac93d8d413ccedbb5208f38e47c47c7b449b10,0000000000000000000000000000000000000000..10433c8d54f2dd1a4fe3211f8e7a60c7c5d33625
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,54 @@@
 +// run-rustfix
 +#![warn(clippy::if_then_panic)]
 +
 +fn main() {
 +    let a = vec![1, 2, 3];
 +    let c = Some(2);
 +    if !a.is_empty()
 +        && a.len() == 3
 +        && c != None
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +        && !a.is_empty()
 +        && a.len() == 3
 +    {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    if !a.is_empty() {
 +        panic!("qaqaq{:?}", a);
 +    }
 +    if !a.is_empty() {
 +        panic!("qwqwq");
 +    }
 +    if a.len() == 3 {
 +        println!("qwq");
 +        println!("qwq");
 +        println!("qwq");
 +    }
 +    if let Some(b) = c {
 +        panic!("orz {}", b);
 +    }
 +    if a.len() == 3 {
 +        panic!("qaqaq");
 +    } else {
 +        println!("qwq");
 +    }
++    let b = vec![1, 2, 3];
++    if b.is_empty() {
++        panic!("panic1");
++    }
++    if b.is_empty() && a.is_empty() {
++        panic!("panic2");
++    }
++    if a.is_empty() && !b.is_empty() {
++        panic!("panic3");
++    }
++    if b.is_empty() || a.is_empty() {
++        panic!("panic4");
++    }
++    if a.is_empty() || !b.is_empty() {
++        panic!("panic5");
++    }
 +}
index b92c9bdf67430872509c0da4429b0d04dde498e1,0000000000000000000000000000000000000000..5bb62f8756606ec42f899d2fec87c4a966d9b48f
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,60 @@@
- error: aborting due to 2 previous errors
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/if_then_panic.rs:19:5
 +   |
 +LL | /     if !a.is_empty() {
 +LL | |         panic!("qaqaq{:?}", a);
 +LL | |     }
 +   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
 +   |
 +   = note: `-D clippy::if-then-panic` implied by `-D warnings`
 +
 +error: only a `panic!` in `if`-then statement
 +  --> $DIR/if_then_panic.rs:22:5
 +   |
 +LL | /     if !a.is_empty() {
 +LL | |         panic!("qwqwq");
 +LL | |     }
 +   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
 +
++error: only a `panic!` in `if`-then statement
++  --> $DIR/if_then_panic.rs:39:5
++   |
++LL | /     if b.is_empty() {
++LL | |         panic!("panic1");
++LL | |     }
++   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/if_then_panic.rs:42:5
++   |
++LL | /     if b.is_empty() && a.is_empty() {
++LL | |         panic!("panic2");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/if_then_panic.rs:45:5
++   |
++LL | /     if a.is_empty() && !b.is_empty() {
++LL | |         panic!("panic3");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/if_then_panic.rs:48:5
++   |
++LL | /     if b.is_empty() || a.is_empty() {
++LL | |         panic!("panic4");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/if_then_panic.rs:51:5
++   |
++LL | /     if a.is_empty() || !b.is_empty() {
++LL | |         panic!("panic5");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
++
++error: aborting due to 7 previous errors
 +
index 97c26bc83ad4b4af2b919c4ecf53c30fcd4fd66a,0000000000000000000000000000000000000000..aa69b0974101c822a06a790c742bed645e46813b
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,103 @@@
++// edition:2018
 +// aux-build:implicit_hasher_macros.rs
 +#![deny(clippy::implicit_hasher)]
 +#![allow(unused)]
 +
 +#[macro_use]
 +extern crate implicit_hasher_macros;
 +
 +use std::cmp::Eq;
 +use std::collections::{HashMap, HashSet};
 +use std::hash::{BuildHasher, Hash};
 +
 +pub trait Foo<T>: Sized {
 +    fn make() -> (Self, Self);
 +}
 +
 +impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
 +    fn make() -> (Self, Self) {
 +        // OK, don't suggest to modify these
 +        let _: HashMap<i32, i32> = HashMap::new();
 +        let _: HashSet<i32> = HashSet::new();
 +
 +        (HashMap::new(), HashMap::with_capacity(10))
 +    }
 +}
 +impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
 +    fn make() -> (Self, Self) {
 +        ((HashMap::new(),), (HashMap::with_capacity(10),))
 +    }
 +}
 +impl Foo<i16> for HashMap<String, String> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::new(), HashMap::with_capacity(10))
 +    }
 +}
 +
 +impl<K: Hash + Eq, V, S: BuildHasher + Default> Foo<i32> for HashMap<K, V, S> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +impl<S: BuildHasher + Default> Foo<i64> for HashMap<String, String, S> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +
 +impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::new(), HashSet::with_capacity(10))
 +    }
 +}
 +impl Foo<i16> for HashSet<String> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::new(), HashSet::with_capacity(10))
 +    }
 +}
 +
 +impl<T: Hash + Eq, S: BuildHasher + Default> Foo<i32> for HashSet<T, S> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +
 +pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +
 +macro_rules! gen {
 +    (impl) => {
 +        impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
 +            fn make() -> (Self, Self) {
 +                (HashMap::new(), HashMap::with_capacity(10))
 +            }
 +        }
 +    };
 +
 +    (fn $name:ident) => {
 +        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +    };
 +}
 +#[rustfmt::skip]
 +gen!(impl);
 +gen!(fn bar);
 +
 +// When the macro is in a different file, the suggestion spans can't be combined properly
 +// and should not cause an ICE
 +// See #2707
 +#[macro_use]
 +#[path = "auxiliary/test_macro.rs"]
 +pub mod test_macro;
 +__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
 +
 +// #4260
 +implicit_hasher_fn!();
 +
++// #7712
++pub async fn election_vote(_data: HashMap<i32, i32>) {}
++
 +fn main() {}
index 2e62dd30f9fc59f7b11ca90b7145a517dc28037f,0000000000000000000000000000000000000000..dad5ab71f157f13a0ff5a23c857223ef83d7cf98
mode 100644,000000..100644
--- /dev/null
@@@ -1,153 -1,0 +1,164 @@@
-   --> $DIR/implicit_hasher.rs:16:35
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:2:9
++  --> $DIR/implicit_hasher.rs:17:35
 +   |
 +LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
 +   |                                   ^^^^^^^^^^^^^
 +   |
 +note: the lint level is defined here
-   --> $DIR/implicit_hasher.rs:25:36
++  --> $DIR/implicit_hasher.rs:3:9
 +   |
 +LL | #![deny(clippy::implicit_hasher)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^
 +help: consider adding a type parameter
 +   |
 +LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:30:19
++  --> $DIR/implicit_hasher.rs:26:36
 +   |
 +LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
 +   |                                    ^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~              ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
 +   |           ~~~~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:47:32
++  --> $DIR/implicit_hasher.rs:31:19
 +   |
 +LL | impl Foo<i16> for HashMap<String, String> {
 +   |                   ^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
 +   |     +++++++++++++++++++++++++++++++++++++++              ~~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:52:19
++  --> $DIR/implicit_hasher.rs:48:32
 +   |
 +LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
 +   |                                ^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:69:23
++  --> $DIR/implicit_hasher.rs:53:19
 +   |
 +LL | impl Foo<i16> for HashSet<String> {
 +   |                   ^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
 +   |     +++++++++++++++++++++++++++++++++++++++              ~~~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:69:53
++  --> $DIR/implicit_hasher.rs:70:23
 +   |
 +LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                       ^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
 +   |           +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:73:43
++  --> $DIR/implicit_hasher.rs:70:53
 +   |
 +LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                                     ^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
 +   |           +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:81:33
++  --> $DIR/implicit_hasher.rs:74:43
 +   |
 +LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
 +   |                                           ^^^^^^^^^^^^^
 +...
 +LL | gen!(impl);
 +   | ----------- in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
 +   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |                  ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:81:63
++  --> $DIR/implicit_hasher.rs:82:33
 +   |
 +LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                 ^^^^^^^^^^^^^^^^^
 +...
 +LL | gen!(fn bar);
 +   | ------------- in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
 +   |                     +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashSet` should be generalized over different hashers
- error: aborting due to 10 previous errors
++  --> $DIR/implicit_hasher.rs:82:63
 +   |
 +LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                                               ^^^^^^^^^^^^
 +...
 +LL | gen!(fn bar);
 +   | ------------- in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
 +   |                     +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 +
++error: parameter of type `HashMap` should be generalized over different hashers
++  --> $DIR/implicit_hasher.rs:101:35
++   |
++LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
++   |                                   ^^^^^^^^^^^^^^^^^
++   |
++help: consider adding a type parameter
++   |
++LL | pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
++   |                           +++++++++++++++++++++++++++++        ~~~~~~~~~~~~~~~~~~~~
++
++error: aborting due to 11 previous errors
 +
index b74c93dc4a666d445b8b324de3c32b4f9c641515,0000000000000000000000000000000000000000..67f24b4548aacacf20ffaea675236c314ff003de
mode 100644,000000..100644
--- /dev/null
@@@ -1,109 -1,0 +1,102 @@@
- #![allow(
-     unused,
-     clippy::shadow_reuse,
-     clippy::shadow_unrelated,
-     clippy::no_effect,
-     clippy::unnecessary_operation,
-     clippy::op_ref
- )]
 +#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)]
 +
 +#[rustfmt::skip]
 +fn main() {
 +    let mut i = 1i32;
 +    let mut var1 = 0i32;
 +    let mut var2 = -1i32;
 +    1 + i;
 +    i * 2;
 +    1 %
 +    i / 2; // no error, this is part of the expression in the preceding line
 +    i - 2 + 2 - i;
 +    -i;
 +    i >> 1;
 +    i << 1;
 +
 +    // no error, overflows are checked by `overflowing_literals`
 +    -1;
 +    -(-1);
 +
 +    i & 1; // no wrapping
 +    i | 1;
 +    i ^ 1;
 +
 +    i += 1;
 +    i -= 1;
 +    i *= 2;
 +    i /= 2;
 +    i /= 0;
 +    i /= -1;
 +    i /= var1;
 +    i /= var2;
 +    i %= 2;
 +    i %= 0;
 +    i %= -1;
 +    i %= var1;
 +    i %= var2;
 +    i <<= 3;
 +    i >>= 2;
 +
 +    // no errors
 +    i |= 1;
 +    i &= 1;
 +    i ^= i;
 +
 +    // No errors for the following items because they are constant expressions
 +    enum Foo {
 +        Bar = -2,
 +    }
 +    struct Baz([i32; 1 + 1]);
 +    union Qux {
 +        field: [i32; 1 + 1],
 +    }
 +    type Alias = [i32; 1 + 1];
 +
 +    const FOO: i32 = -2;
 +    static BAR: i32 = -2;
 +
 +    let _: [i32; 1 + 1] = [0, 0];
 +
 +    let _: [i32; 1 + 1] = {
 +        let a: [i32; 1 + 1] = [0, 0];
 +        a
 +    };
 +
 +    trait Trait {
 +        const ASSOC: i32 = 1 + 1;
 +    }
 +
 +    impl Trait for Foo {
 +        const ASSOC: i32 = {
 +            let _: [i32; 1 + 1];
 +            fn foo() {}
 +            1 + 1
 +        };
 +    }
 +}
 +
 +// warn on references as well! (#5328)
 +pub fn int_arith_ref() {
 +    3 + &1;
 +    &3 + 1;
 +    &3 + &1;
 +}
 +
 +pub fn foo(x: &i32) -> i32 {
 +    let a = 5;
 +    a + x
 +}
 +
 +pub fn bar(x: &i32, y: &i32) -> i32 {
 +    x + y
 +}
 +
 +pub fn baz(x: i32, y: &i32) -> i32 {
 +    x + y
 +}
 +
 +pub fn qux(x: i32, y: i32) -> i32 {
 +    (&x + &y)
 +}
index add3b6b90fa26108cb534a9f93e11cc8b167582c,0000000000000000000000000000000000000000..9a795b1f291547c9f8e3a06990a7901761d3ce7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,169 -1,0 +1,169 @@@
-   --> $DIR/integer_arithmetic.rs:37:5
 +error: this operation will panic at runtime
-   --> $DIR/integer_arithmetic.rs:42:5
++  --> $DIR/integer_arithmetic.rs:30:5
 +   |
 +LL |     i /= 0;
 +   |     ^^^^^^ attempt to divide `_` by zero
 +   |
 +   = note: `#[deny(unconditional_panic)]` on by default
 +
 +error: this operation will panic at runtime
-   --> $DIR/integer_arithmetic.rs:16:5
++  --> $DIR/integer_arithmetic.rs:35:5
 +   |
 +LL |     i %= 0;
 +   |     ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:17:5
++  --> $DIR/integer_arithmetic.rs:9:5
 +   |
 +LL |     1 + i;
 +   |     ^^^^^
 +   |
 +   = note: `-D clippy::integer-arithmetic` implied by `-D warnings`
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:18:5
++  --> $DIR/integer_arithmetic.rs:10:5
 +   |
 +LL |     i * 2;
 +   |     ^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:20:5
++  --> $DIR/integer_arithmetic.rs:11:5
 +   |
 +LL | /     1 %
 +LL | |     i / 2; // no error, this is part of the expression in the preceding line
 +   | |_____^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:21:5
++  --> $DIR/integer_arithmetic.rs:13:5
 +   |
 +LL |     i - 2 + 2 - i;
 +   |     ^^^^^^^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:22:5
++  --> $DIR/integer_arithmetic.rs:14:5
 +   |
 +LL |     -i;
 +   |     ^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:23:5
++  --> $DIR/integer_arithmetic.rs:15:5
 +   |
 +LL |     i >> 1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:33:5
++  --> $DIR/integer_arithmetic.rs:16:5
 +   |
 +LL |     i << 1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:34:5
++  --> $DIR/integer_arithmetic.rs:26:5
 +   |
 +LL |     i += 1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:35:5
++  --> $DIR/integer_arithmetic.rs:27:5
 +   |
 +LL |     i -= 1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:38:11
++  --> $DIR/integer_arithmetic.rs:28:5
 +   |
 +LL |     i *= 2;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:39:5
++  --> $DIR/integer_arithmetic.rs:31:11
 +   |
 +LL |     i /= -1;
 +   |           ^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:40:5
++  --> $DIR/integer_arithmetic.rs:32:5
 +   |
 +LL |     i /= var1;
 +   |     ^^^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:43:11
++  --> $DIR/integer_arithmetic.rs:33:5
 +   |
 +LL |     i /= var2;
 +   |     ^^^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:44:5
++  --> $DIR/integer_arithmetic.rs:36:11
 +   |
 +LL |     i %= -1;
 +   |           ^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:45:5
++  --> $DIR/integer_arithmetic.rs:37:5
 +   |
 +LL |     i %= var1;
 +   |     ^^^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:46:5
++  --> $DIR/integer_arithmetic.rs:38:5
 +   |
 +LL |     i %= var2;
 +   |     ^^^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:47:5
++  --> $DIR/integer_arithmetic.rs:39:5
 +   |
 +LL |     i <<= 3;
 +   |     ^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:89:5
++  --> $DIR/integer_arithmetic.rs:40:5
 +   |
 +LL |     i >>= 2;
 +   |     ^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:90:5
++  --> $DIR/integer_arithmetic.rs:82:5
 +   |
 +LL |     3 + &1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:91:5
++  --> $DIR/integer_arithmetic.rs:83:5
 +   |
 +LL |     &3 + 1;
 +   |     ^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:96:5
++  --> $DIR/integer_arithmetic.rs:84:5
 +   |
 +LL |     &3 + &1;
 +   |     ^^^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:100:5
++  --> $DIR/integer_arithmetic.rs:89:5
 +   |
 +LL |     a + x
 +   |     ^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:104:5
++  --> $DIR/integer_arithmetic.rs:93:5
 +   |
 +LL |     x + y
 +   |     ^^^^^
 +
 +error: integer arithmetic detected
-   --> $DIR/integer_arithmetic.rs:108:5
++  --> $DIR/integer_arithmetic.rs:97:5
 +   |
 +LL |     x + y
 +   |     ^^^^^
 +
 +error: integer arithmetic detected
++  --> $DIR/integer_arithmetic.rs:101:5
 +   |
 +LL |     (&x + &y)
 +   |     ^^^^^^^^^
 +
 +error: aborting due to 27 previous errors
 +
index d22fee3f27b05818c3ed86e1127c010726bb7afa,0000000000000000000000000000000000000000..b45cc849eaec42b5796e35d196f55aee7d312e46
mode 100644,000000..100644
--- /dev/null
@@@ -1,61 -1,0 +1,79 @@@
 +// aux-build:macro_rules.rs
 +
 +#![allow(dead_code)]
 +#![allow(unused_variables)]
 +#![warn(clippy::large_enum_variant)]
 +
 +#[macro_use]
 +extern crate macro_rules;
 +
 +enum LargeEnum {
 +    A(i32),
 +    B([i32; 8000]),
 +}
 +
 +enum GenericEnumOk<T> {
 +    A(i32),
 +    B([T; 8000]),
 +}
 +
 +enum GenericEnum2<T> {
 +    A(i32),
 +    B([i32; 8000]),
 +    C(T, [i32; 8000]),
 +}
 +
 +trait SomeTrait {
 +    type Item;
 +}
 +
 +enum LargeEnumGeneric<A: SomeTrait> {
 +    Var(A::Item),
 +}
 +
 +enum LargeEnum2 {
 +    VariantOk(i32, u32),
 +    ContainingLargeEnum(LargeEnum),
 +}
++
 +enum LargeEnum3 {
 +    ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
 +    VoidVariant,
 +    StructLikeLittle { x: i32, y: i32 },
 +}
 +
 +enum LargeEnum4 {
 +    VariantOk(i32, u32),
 +    StructLikeLarge { x: [i32; 8000], y: i32 },
 +}
 +
 +enum LargeEnum5 {
 +    VariantOk(i32, u32),
 +    StructLikeLarge2 { x: [i32; 8000] },
 +}
 +
 +enum LargeEnumOk {
 +    LargeA([i32; 8000]),
 +    LargeB([i32; 8001]),
 +}
 +
++enum LargeEnum6 {
++    A,
++    B([u8; 255]),
++    C([u8; 200]),
++}
++
++enum LargeEnum7 {
++    A,
++    B([u8; 1255]),
++    C([u8; 200]),
++}
++
++enum LargeEnum8 {
++    VariantOk(i32, u32),
++    ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
++}
++
 +fn main() {
 +    large_enum_variant!();
 +}
index 0eac28fbd35003d6a1c8009f6eeb59de653ac9eb,0000000000000000000000000000000000000000..899f97ce2e1e91ba4f3ce50e9cfb39ce2cd8c0b2
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,115 @@@
-   --> $DIR/large_enum_variant.rs:46:5
 +error: large size difference between variants
 +  --> $DIR/large_enum_variant.rs:12:5
 +   |
 +LL |     B([i32; 8000]),
 +   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
 +   |
 +   = note: `-D clippy::large-enum-variant` implied by `-D warnings`
 +note: and the second-largest variant is 4 bytes:
 +  --> $DIR/large_enum_variant.rs:11:5
 +   |
 +LL |     A(i32),
 +   |     ^^^^^^
 +help: consider boxing the large fields to reduce the total size of the enum
 +   |
 +LL |     B(Box<[i32; 8000]>),
 +   |       ~~~~~~~~~~~~~~~~
 +
 +error: large size difference between variants
 +  --> $DIR/large_enum_variant.rs:36:5
 +   |
 +LL |     ContainingLargeEnum(LargeEnum),
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
 +   |
 +note: and the second-largest variant is 8 bytes:
 +  --> $DIR/large_enum_variant.rs:35:5
 +   |
 +LL |     VariantOk(i32, u32),
 +   |     ^^^^^^^^^^^^^^^^^^^
 +help: consider boxing the large fields to reduce the total size of the enum
 +   |
 +LL |     ContainingLargeEnum(Box<LargeEnum>),
 +   |                         ~~~~~~~~~~~~~~
 +
 +error: large size difference between variants
-   --> $DIR/large_enum_variant.rs:45:5
++  --> $DIR/large_enum_variant.rs:40:5
++   |
++LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
++   |
++note: and the second-largest variant is 8 bytes:
++  --> $DIR/large_enum_variant.rs:42:5
++   |
++LL |     StructLikeLittle { x: i32, y: i32 },
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++help: consider boxing the large fields to reduce the total size of the enum
++   |
++LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
++   |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
++
++error: large size difference between variants
++  --> $DIR/large_enum_variant.rs:47:5
 +   |
 +LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
 +   |
 +note: and the second-largest variant is 8 bytes:
-   --> $DIR/large_enum_variant.rs:46:5
++  --> $DIR/large_enum_variant.rs:46:5
 +   |
 +LL |     VariantOk(i32, u32),
 +   |     ^^^^^^^^^^^^^^^^^^^
 +help: consider boxing the large fields to reduce the total size of the enum
- LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
-   --> $DIR/large_enum_variant.rs:51:5
++LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
++   |                          ~~~~~~~~~~~~~~~~
 +
 +error: large size difference between variants
-   --> $DIR/large_enum_variant.rs:50:5
++  --> $DIR/large_enum_variant.rs:52:5
 +   |
 +LL |     StructLikeLarge2 { x: [i32; 8000] },
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
 +   |
 +note: and the second-largest variant is 8 bytes:
- error: aborting due to 4 previous errors
++  --> $DIR/large_enum_variant.rs:51:5
 +   |
 +LL |     VariantOk(i32, u32),
 +   |     ^^^^^^^^^^^^^^^^^^^
 +help: consider boxing the large fields to reduce the total size of the enum
 +   |
 +LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
 +   |                           ~~~~~~~~~~~~~~~~
 +
++error: large size difference between variants
++  --> $DIR/large_enum_variant.rs:68:5
++   |
++LL |     B([u8; 1255]),
++   |     ^^^^^^^^^^^^^ this variant is 1255 bytes
++   |
++note: and the second-largest variant is 200 bytes:
++  --> $DIR/large_enum_variant.rs:69:5
++   |
++LL |     C([u8; 200]),
++   |     ^^^^^^^^^^^^
++help: consider boxing the large fields to reduce the total size of the enum
++   |
++LL |     B(Box<[u8; 1255]>),
++   |       ~~~~~~~~~~~~~~~
++
++error: large size difference between variants
++  --> $DIR/large_enum_variant.rs:74:5
++   |
++LL |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
++   |
++note: and the second-largest variant is 8 bytes:
++  --> $DIR/large_enum_variant.rs:73:5
++   |
++LL |     VariantOk(i32, u32),
++   |     ^^^^^^^^^^^^^^^^^^^
++help: consider boxing the large fields to reduce the total size of the enum
++   |
++LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
++   |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
++
++error: aborting due to 7 previous errors
 +
index 178d8705c2f02cedf1a70ed5ef6604e802fd873d,0000000000000000000000000000000000000000..0860dcf8e0ddb610a1ec41cb65f0fd23b94752d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,63 @@@
- #![warn(clippy::all, clippy::pedantic)]
- #![allow(clippy::iter_cloned_collect)]
- #![allow(clippy::clone_on_copy, clippy::redundant_clone)]
- #![allow(clippy::let_underscore_drop)]
- #![allow(clippy::missing_docs_in_private_items)]
- #![allow(clippy::redundant_closure_for_method_calls)]
- #![allow(clippy::many_single_char_names)]
 +// run-rustfix
++#![warn(clippy::map_clone)]
++#![allow(
++    clippy::clone_on_copy,
++    clippy::iter_cloned_collect,
++    clippy::many_single_char_names,
++    clippy::redundant_clone
++)]
 +
 +fn main() {
 +    let _: Vec<i8> = vec![5_i8; 6].iter().copied().collect();
 +    let _: Vec<String> = vec![String::new()].iter().cloned().collect();
 +    let _: Vec<u32> = vec![42, 43].iter().copied().collect();
 +    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
 +    let _: Option<u64> = Some(&16).copied();
 +    let _: Option<u8> = Some(&1).copied();
 +
 +    // Don't lint these
 +    let v = vec![5_i8; 6];
 +    let a = 0;
 +    let b = &a;
 +    let _ = v.iter().map(|_x| *b);
 +    let _ = v.iter().map(|_x| a.clone());
 +    let _ = v.iter().map(|&_x| a);
 +
 +    // Issue #498
 +    let _ = std::env::args();
 +
 +    // Issue #4824 item types that aren't references
 +    {
 +        use std::rc::Rc;
 +
 +        let o: Option<Rc<u32>> = Some(Rc::new(0_u32));
 +        let _: Option<u32> = o.map(|x| *x);
 +        let v: Vec<Rc<u32>> = vec![Rc::new(0_u32)];
 +        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
 +    }
 +
 +    // Issue #5524 mutable references
 +    {
 +        let mut c = 42;
 +        let v = vec![&mut c];
 +        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
 +        let mut d = 21;
 +        let v = vec![&mut d];
 +        let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
 +    }
 +
 +    // Issue #6299
 +    {
 +        let mut aa = 5;
 +        let mut bb = 3;
 +        let items = vec![&mut aa, &mut bb];
 +        let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
 +    }
 +
 +    // Issue #6239 deref coercion and clone deref
 +    {
 +        use std::cell::RefCell;
 +
 +        let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
 +    }
 +}
index c73d81713b8a3a762adf71fa13589f65640d9463,0000000000000000000000000000000000000000..b6987336834b84dec65af32aba776a0facbd0150
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,63 @@@
- #![warn(clippy::all, clippy::pedantic)]
- #![allow(clippy::iter_cloned_collect)]
- #![allow(clippy::clone_on_copy, clippy::redundant_clone)]
- #![allow(clippy::let_underscore_drop)]
- #![allow(clippy::missing_docs_in_private_items)]
- #![allow(clippy::redundant_closure_for_method_calls)]
- #![allow(clippy::many_single_char_names)]
 +// run-rustfix
++#![warn(clippy::map_clone)]
++#![allow(
++    clippy::clone_on_copy,
++    clippy::iter_cloned_collect,
++    clippy::many_single_char_names,
++    clippy::redundant_clone
++)]
 +
 +fn main() {
 +    let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
 +    let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
 +    let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
 +    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
 +    let _: Option<u64> = Some(&16).map(|b| *b);
 +    let _: Option<u8> = Some(&1).map(|x| x.clone());
 +
 +    // Don't lint these
 +    let v = vec![5_i8; 6];
 +    let a = 0;
 +    let b = &a;
 +    let _ = v.iter().map(|_x| *b);
 +    let _ = v.iter().map(|_x| a.clone());
 +    let _ = v.iter().map(|&_x| a);
 +
 +    // Issue #498
 +    let _ = std::env::args().map(|v| v.clone());
 +
 +    // Issue #4824 item types that aren't references
 +    {
 +        use std::rc::Rc;
 +
 +        let o: Option<Rc<u32>> = Some(Rc::new(0_u32));
 +        let _: Option<u32> = o.map(|x| *x);
 +        let v: Vec<Rc<u32>> = vec![Rc::new(0_u32)];
 +        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
 +    }
 +
 +    // Issue #5524 mutable references
 +    {
 +        let mut c = 42;
 +        let v = vec![&mut c];
 +        let _: Vec<u32> = v.into_iter().map(|x| *x).collect();
 +        let mut d = 21;
 +        let v = vec![&mut d];
 +        let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
 +    }
 +
 +    // Issue #6299
 +    {
 +        let mut aa = 5;
 +        let mut bb = 3;
 +        let items = vec![&mut aa, &mut bb];
 +        let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
 +    }
 +
 +    // Issue #6239 deref coercion and clone deref
 +    {
 +        use std::cell::RefCell;
 +
 +        let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
 +    }
 +}
index 319299862a7003462cbaffe429edb6235c28f482,0000000000000000000000000000000000000000..c611f76bf96055704ebb37927cf3ec16ae2765d4
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,149 @@@
- #![allow(unreachable_patterns, dead_code)]
 +// run-rustfix
 +
 +#![warn(clippy::match_like_matches_macro)]
++#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
 +
 +fn main() {
 +    let x = Some(5);
 +
 +    // Lint
 +    let _y = matches!(x, Some(0));
 +
 +    // Lint
 +    let _w = matches!(x, Some(_));
 +
 +    // Turn into is_none
 +    let _z = x.is_none();
 +
 +    // Lint
 +    let _zz = !matches!(x, Some(r) if r == 0);
 +
 +    // Lint
 +    let _zzz = matches!(x, Some(5));
 +
 +    // No lint
 +    let _a = match x {
 +        Some(_) => false,
 +        _ => false,
 +    };
 +
 +    // No lint
 +    let _ab = match x {
 +        Some(0) => false,
 +        _ => true,
 +        None => false,
 +    };
 +
 +    enum E {
 +        A(u32),
 +        B(i32),
 +        C,
 +        D,
 +    }
 +    let x = E::A(2);
 +    {
 +        // lint
 +        let _ans = matches!(x, E::A(_) | E::B(_));
 +    }
 +    {
 +        // lint
 +        let _ans = !matches!(x, E::B(_) | E::C);
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(_) => false,
 +            E::C => true,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => true,
 +            E::B(_) => false,
 +            E::C => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(a) if a < 10 => false,
 +            E::B(a) if a < 10 => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(a) if a < 10 => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(a) => a == 10,
 +            E::B(_) => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(_) => true,
 +            _ => false,
 +        };
 +    }
 +
 +    {
 +        // should print "z" in suggestion (#6503)
 +        let z = &Some(3);
 +        let _z = matches!(z, Some(3));
 +    }
 +
 +    {
 +        // this could also print "z" in suggestion..?
 +        let z = Some(3);
 +        let _z = matches!(&z, Some(3));
 +    }
 +
 +    {
 +        enum AnEnum {
 +            X,
 +            Y,
 +        }
 +
 +        fn foo(_x: AnEnum) {}
 +
 +        fn main() {
 +            let z = AnEnum::X;
 +            // we can't remove the reference here!
 +            let _ = matches!(&z, AnEnum::X);
 +            foo(z);
 +        }
 +    }
 +
 +    {
 +        struct S(i32);
 +
 +        fn fun(_val: Option<S>) {}
 +        let val = Some(S(42));
 +        // we need the reference here because later val is consumed by fun()
 +        let _res = matches!(&val, &Some(ref _a));
 +        fun(val);
 +    }
 +
 +    {
 +        struct S(i32);
 +
 +        fn fun(_val: Option<S>) {}
 +        let val = Some(S(42));
 +        let _res = matches!(&val, &Some(ref _a));
 +        fun(val);
 +    }
 +}
index 2ef6cf42387f6e5b5cd71d788fbabe4f8f7ac01d,0000000000000000000000000000000000000000..2deeb84e74138151920ca91279cef789ebad2e79
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,184 @@@
- #![allow(unreachable_patterns, dead_code)]
 +// run-rustfix
 +
 +#![warn(clippy::match_like_matches_macro)]
++#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
 +
 +fn main() {
 +    let x = Some(5);
 +
 +    // Lint
 +    let _y = match x {
 +        Some(0) => true,
 +        _ => false,
 +    };
 +
 +    // Lint
 +    let _w = match x {
 +        Some(_) => true,
 +        _ => false,
 +    };
 +
 +    // Turn into is_none
 +    let _z = match x {
 +        Some(_) => false,
 +        None => true,
 +    };
 +
 +    // Lint
 +    let _zz = match x {
 +        Some(r) if r == 0 => false,
 +        _ => true,
 +    };
 +
 +    // Lint
 +    let _zzz = if let Some(5) = x { true } else { false };
 +
 +    // No lint
 +    let _a = match x {
 +        Some(_) => false,
 +        _ => false,
 +    };
 +
 +    // No lint
 +    let _ab = match x {
 +        Some(0) => false,
 +        _ => true,
 +        None => false,
 +    };
 +
 +    enum E {
 +        A(u32),
 +        B(i32),
 +        C,
 +        D,
 +    }
 +    let x = E::A(2);
 +    {
 +        // lint
 +        let _ans = match x {
 +            E::A(_) => true,
 +            E::B(_) => true,
 +            _ => false,
 +        };
 +    }
 +    {
 +        // lint
 +        let _ans = match x {
 +            E::B(_) => false,
 +            E::C => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(_) => false,
 +            E::C => true,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => true,
 +            E::B(_) => false,
 +            E::C => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(a) if a < 10 => false,
 +            E::B(a) if a < 10 => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(a) if a < 10 => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(a) => a == 10,
 +            E::B(_) => false,
 +            _ => true,
 +        };
 +    }
 +    {
 +        // no lint
 +        let _ans = match x {
 +            E::A(_) => false,
 +            E::B(_) => true,
 +            _ => false,
 +        };
 +    }
 +
 +    {
 +        // should print "z" in suggestion (#6503)
 +        let z = &Some(3);
 +        let _z = match &z {
 +            Some(3) => true,
 +            _ => false,
 +        };
 +    }
 +
 +    {
 +        // this could also print "z" in suggestion..?
 +        let z = Some(3);
 +        let _z = match &z {
 +            Some(3) => true,
 +            _ => false,
 +        };
 +    }
 +
 +    {
 +        enum AnEnum {
 +            X,
 +            Y,
 +        }
 +
 +        fn foo(_x: AnEnum) {}
 +
 +        fn main() {
 +            let z = AnEnum::X;
 +            // we can't remove the reference here!
 +            let _ = match &z {
 +                AnEnum::X => true,
 +                _ => false,
 +            };
 +            foo(z);
 +        }
 +    }
 +
 +    {
 +        struct S(i32);
 +
 +        fn fun(_val: Option<S>) {}
 +        let val = Some(S(42));
 +        // we need the reference here because later val is consumed by fun()
 +        let _res = match &val {
 +            &Some(ref _a) => true,
 +            _ => false,
 +        };
 +        fun(val);
 +    }
 +
 +    {
 +        struct S(i32);
 +
 +        fn fun(_val: Option<S>) {}
 +        let val = Some(S(42));
 +        let _res = match &val {
 +            &Some(ref _a) => true,
 +            _ => false,
 +        };
 +        fun(val);
 +    }
 +}
index c84e31ea482a48e8fefc32c8d43912acb2e3b874,0000000000000000000000000000000000000000..846d665d1d864d86dd9396dc23a379271252cb8e
mode 100644,000000..100644
--- /dev/null
@@@ -1,113 -1,0 +1,113 @@@
- #![allow(clippy::if_same_then_else)]
 +#![feature(exclusive_range_pattern)]
 +#![feature(half_open_range_patterns)]
 +#![warn(clippy::match_overlapping_arm)]
 +#![allow(clippy::redundant_pattern_matching)]
++#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
 +
 +/// Tests for match_overlapping_arm
 +
 +fn overlapping() {
 +    const FOO: u64 = 2;
 +
 +    match 42 {
 +        0..=10 => println!("0 ... 10"),
 +        0..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..=5 => println!("0 ... 5"),
 +        6..=7 => println!("6 ... 7"),
 +        FOO..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..=5 => println!("0 ... 5"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..=2 => println!("0 ... 2"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..=10 => println!("0 ... 10"),
 +        11..=50 => println!("11 ... 50"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..2 => println!("0 .. 2"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..10 => println!("0 .. 10"),
 +        10..50 => println!("10 .. 50"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..11 => println!("0 .. 11"),
 +        0..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        5..7 => println!("5 .. 7"),
 +        0..10 => println!("0 .. 10"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        5..10 => println!("5 .. 10"),
 +        0..=10 => println!("0 ... 10"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..14 => println!("0 .. 14"),
 +        5..10 => println!("5 .. 10"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        5..14 => println!("5 .. 14"),
 +        0..=10 => println!("0 ... 10"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..7 => println!("0 .. 7"),
 +        0..=10 => println!("0 ... 10"),
 +        _ => (),
 +    }
 +
 +    /*
 +    // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
 +    match 42 {
 +        0.. => println!("0 .. 42"),
 +        3.. => println!("3 .. 42"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        ..=23 => println!("0 ... 23"),
 +        ..26 => println!("0 .. 26"),
 +        _ => (),
 +    }
 +    */
 +
 +    if let None = Some(42) {
 +        // nothing
 +    } else if let None = Some(42) {
 +        // another nothing :-)
 +    }
 +}
 +
 +fn main() {}
index 5de43733ad33601a1108985bdb686b0d10d332e1,0000000000000000000000000000000000000000..6cbb4d32b0d71287c8e35a8e648d9436cbb0aef5
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,75 @@@
 +#![warn(clippy::match_ref_pats)]
++#![allow(clippy::equatable_if_let)]
 +
 +fn ref_pats() {
 +    {
 +        let v = &Some(0);
 +        match v {
 +            &Some(v) => println!("{:?}", v),
 +            &None => println!("none"),
 +        }
 +        match v {
 +            // This doesn't trigger; we have a different pattern.
 +            &Some(v) => println!("some"),
 +            other => println!("other"),
 +        }
 +    }
 +    let tup = &(1, 2);
 +    match tup {
 +        &(v, 1) => println!("{}", v),
 +        _ => println!("none"),
 +    }
 +    // Special case: using `&` both in expr and pats.
 +    let w = Some(0);
 +    match &w {
 +        &Some(v) => println!("{:?}", v),
 +        &None => println!("none"),
 +    }
 +    // False positive: only wildcard pattern.
 +    let w = Some(0);
 +    #[allow(clippy::match_single_binding)]
 +    match w {
 +        _ => println!("none"),
 +    }
 +
 +    let a = &Some(0);
 +    if let &None = a {
 +        println!("none");
 +    }
 +
 +    let b = Some(0);
 +    if let &None = &b {
 +        println!("none");
 +    }
 +}
 +
 +mod ice_3719 {
 +    macro_rules! foo_variant(
 +        ($idx:expr) => (Foo::get($idx).unwrap())
 +    );
 +
 +    enum Foo {
 +        A,
 +        B,
 +    }
 +
 +    impl Foo {
 +        fn get(idx: u8) -> Option<&'static Self> {
 +            match idx {
 +                0 => Some(&Foo::A),
 +                1 => Some(&Foo::B),
 +                _ => None,
 +            }
 +        }
 +    }
 +
 +    fn ice_3719() {
 +        // ICE #3719
 +        match foo_variant!(0) {
 +            &Foo::A => println!("A"),
 +            _ => println!("Wild"),
 +        }
 +    }
 +}
 +
 +fn main() {}
index a57a338b2763434e95af9ee7b94606447ddab33f,0000000000000000000000000000000000000000..072aff445e97f2b330a4fdc56e58bff33fa5a1b1
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,105 @@@
-   --> $DIR/match_ref_pats.rs:6:9
 +error: you don't need to add `&` to all patterns
-   --> $DIR/match_ref_pats.rs:17:5
++  --> $DIR/match_ref_pats.rs:7:9
 +   |
 +LL | /         match v {
 +LL | |             &Some(v) => println!("{:?}", v),
 +LL | |             &None => println!("none"),
 +LL | |         }
 +   | |_________^
 +   |
 +   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
 +help: instead of prefixing all patterns with `&`, you can dereference the expression
 +   |
 +LL ~         match *v {
 +LL ~             Some(v) => println!("{:?}", v),
 +LL ~             None => println!("none"),
 +   |
 +
 +error: you don't need to add `&` to all patterns
-   --> $DIR/match_ref_pats.rs:23:5
++  --> $DIR/match_ref_pats.rs:18:5
 +   |
 +LL | /     match tup {
 +LL | |         &(v, 1) => println!("{}", v),
 +LL | |         _ => println!("none"),
 +LL | |     }
 +   | |_____^
 +   |
 +help: instead of prefixing all patterns with `&`, you can dereference the expression
 +   |
 +LL ~     match *tup {
 +LL ~         (v, 1) => println!("{}", v),
 +   |
 +
 +error: you don't need to add `&` to both the expression and the patterns
-   --> $DIR/match_ref_pats.rs:35:12
++  --> $DIR/match_ref_pats.rs:24:5
 +   |
 +LL | /     match &w {
 +LL | |         &Some(v) => println!("{:?}", v),
 +LL | |         &None => println!("none"),
 +LL | |     }
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     match w {
 +LL ~         Some(v) => println!("{:?}", v),
 +LL ~         None => println!("none"),
 +   |
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/match_ref_pats.rs:35:5
++  --> $DIR/match_ref_pats.rs:36:12
 +   |
 +LL |     if let &None = a {
 +   |     -------^^^^^---- help: try this: `if a.is_none()`
 +   |
 +   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 +
 +error: you don't need to add `&` to all patterns
-   --> $DIR/match_ref_pats.rs:40:12
++  --> $DIR/match_ref_pats.rs:36:5
 +   |
 +LL | /     if let &None = a {
 +LL | |         println!("none");
 +LL | |     }
 +   | |_____^
 +   |
 +help: instead of prefixing all patterns with `&`, you can dereference the expression
 +   |
 +LL |     if let None = *a {
 +   |            ~~~~   ~~
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/match_ref_pats.rs:40:5
++  --> $DIR/match_ref_pats.rs:41:12
 +   |
 +LL |     if let &None = &b {
 +   |     -------^^^^^----- help: try this: `if b.is_none()`
 +
 +error: you don't need to add `&` to both the expression and the patterns
-   --> $DIR/match_ref_pats.rs:67:9
++  --> $DIR/match_ref_pats.rs:41:5
 +   |
 +LL | /     if let &None = &b {
 +LL | |         println!("none");
 +LL | |     }
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL |     if let None = b {
 +   |            ~~~~   ~
 +
 +error: you don't need to add `&` to all patterns
++  --> $DIR/match_ref_pats.rs:68:9
 +   |
 +LL | /         match foo_variant!(0) {
 +LL | |             &Foo::A => println!("A"),
 +LL | |             _ => println!("Wild"),
 +LL | |         }
 +   | |_________^
 +   |
 +help: instead of prefixing all patterns with `&`, you can dereference the expression
 +   |
 +LL ~         match *foo_variant!(0) {
 +LL ~             Foo::A => println!("A"),
 +   |
 +
 +error: aborting due to 8 previous errors
 +
index b010b0dbdfa69e5c241745a70ddf6eaef7a1d42a,0000000000000000000000000000000000000000..b1861f07cd189f4454f5238364825d8f072fccae
mode 100644,000000..100644
--- /dev/null
@@@ -1,36 -1,0 +1,29 @@@
- #![allow(
-     unused,
-     clippy::shadow_reuse,
-     clippy::shadow_unrelated,
-     clippy::no_effect,
-     clippy::unnecessary_operation,
-     clippy::modulo_one
- )]
 +#![warn(clippy::modulo_arithmetic)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
 +
 +fn main() {
 +    // Lint when both sides are const and of the opposite sign
 +    -1.6 % 2.1;
 +    1.6 % -2.1;
 +    (1.1 - 2.3) % (1.1 + 2.3);
 +    (1.1 + 2.3) % (1.1 - 2.3);
 +
 +    // Lint on floating point numbers
 +    let a_f32: f32 = -1.6;
 +    let mut b_f32: f32 = 2.1;
 +    a_f32 % b_f32;
 +    b_f32 % a_f32;
 +    b_f32 %= a_f32;
 +
 +    let a_f64: f64 = -1.6;
 +    let mut b_f64: f64 = 2.1;
 +    a_f64 % b_f64;
 +    b_f64 % a_f64;
 +    b_f64 %= a_f64;
 +
 +    // No lint when both sides are const and of the same sign
 +    1.6 % 2.1;
 +    -1.6 % -2.1;
 +    (1.1 + 2.3) % (-1.1 + 2.3);
 +    (-1.1 - 2.3) % (1.1 - 2.3);
 +}
index 7bfdb0bde60706bc3765f87bd98a02211cde1265,0000000000000000000000000000000000000000..97844aaaa7598d2587fae9e02cfdbf2dc56ed471
mode 100644,000000..100644
--- /dev/null
@@@ -1,83 -1,0 +1,83 @@@
-   --> $DIR/modulo_arithmetic_float.rs:13:5
 +error: you are using modulo operator on constants with different signs: `-1.600 % 2.100`
-   --> $DIR/modulo_arithmetic_float.rs:14:5
++  --> $DIR/modulo_arithmetic_float.rs:6:5
 +   |
 +LL |     -1.6 % 2.1;
 +   |     ^^^^^^^^^^
 +   |
 +   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on constants with different signs: `1.600 % -2.100`
-   --> $DIR/modulo_arithmetic_float.rs:15:5
++  --> $DIR/modulo_arithmetic_float.rs:7:5
 +   |
 +LL |     1.6 % -2.1;
 +   |     ^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on constants with different signs: `-1.200 % 3.400`
-   --> $DIR/modulo_arithmetic_float.rs:16:5
++  --> $DIR/modulo_arithmetic_float.rs:8:5
 +   |
 +LL |     (1.1 - 2.3) % (1.1 + 2.3);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on constants with different signs: `3.400 % -1.200`
-   --> $DIR/modulo_arithmetic_float.rs:21:5
++  --> $DIR/modulo_arithmetic_float.rs:9:5
 +   |
 +LL |     (1.1 + 2.3) % (1.1 - 2.3);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_float.rs:22:5
++  --> $DIR/modulo_arithmetic_float.rs:14:5
 +   |
 +LL |     a_f32 % b_f32;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_float.rs:23:5
++  --> $DIR/modulo_arithmetic_float.rs:15:5
 +   |
 +LL |     b_f32 % a_f32;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_float.rs:27:5
++  --> $DIR/modulo_arithmetic_float.rs:16:5
 +   |
 +LL |     b_f32 %= a_f32;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_float.rs:28:5
++  --> $DIR/modulo_arithmetic_float.rs:20:5
 +   |
 +LL |     a_f64 % b_f64;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_float.rs:29:5
++  --> $DIR/modulo_arithmetic_float.rs:21:5
 +   |
 +LL |     b_f64 % a_f64;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: you are using modulo operator on types that might have different signs
++  --> $DIR/modulo_arithmetic_float.rs:22:5
 +   |
 +LL |     b_f64 %= a_f64;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +
 +error: aborting due to 10 previous errors
 +
index 779d035c5f8a28850939afd1000a494b2fb737cc,0000000000000000000000000000000000000000..fc1acc39ebc776828508b1d2a6a69cfcb5573616
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,83 @@@
- #![allow(
-     unused,
-     clippy::shadow_reuse,
-     clippy::shadow_unrelated,
-     clippy::no_effect,
-     clippy::unnecessary_operation,
-     clippy::modulo_one
- )]
 +#![warn(clippy::modulo_arithmetic)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
 +
 +fn main() {
 +    // Lint on signed integral numbers
 +    let a = -1;
 +    let mut b = 2;
 +    a % b;
 +    b % a;
 +    b %= a;
 +
 +    let a_i8: i8 = 1;
 +    let mut b_i8: i8 = 2;
 +    a_i8 % b_i8;
 +    b_i8 %= a_i8;
 +
 +    let a_i16: i16 = 1;
 +    let mut b_i16: i16 = 2;
 +    a_i16 % b_i16;
 +    b_i16 %= a_i16;
 +
 +    let a_i32: i32 = 1;
 +    let mut b_i32: i32 = 2;
 +    a_i32 % b_i32;
 +    b_i32 %= a_i32;
 +
 +    let a_i64: i64 = 1;
 +    let mut b_i64: i64 = 2;
 +    a_i64 % b_i64;
 +    b_i64 %= a_i64;
 +
 +    let a_i128: i128 = 1;
 +    let mut b_i128: i128 = 2;
 +    a_i128 % b_i128;
 +    b_i128 %= a_i128;
 +
 +    let a_isize: isize = 1;
 +    let mut b_isize: isize = 2;
 +    a_isize % b_isize;
 +    b_isize %= a_isize;
 +
 +    let a = 1;
 +    let mut b = 2;
 +    a % b;
 +    b %= a;
 +
 +    // No lint on unsigned integral value
 +    let a_u8: u8 = 17;
 +    let b_u8: u8 = 3;
 +    a_u8 % b_u8;
 +    let mut a_u8: u8 = 1;
 +    a_u8 %= 2;
 +
 +    let a_u16: u16 = 17;
 +    let b_u16: u16 = 3;
 +    a_u16 % b_u16;
 +    let mut a_u16: u16 = 1;
 +    a_u16 %= 2;
 +
 +    let a_u32: u32 = 17;
 +    let b_u32: u32 = 3;
 +    a_u32 % b_u32;
 +    let mut a_u32: u32 = 1;
 +    a_u32 %= 2;
 +
 +    let a_u64: u64 = 17;
 +    let b_u64: u64 = 3;
 +    a_u64 % b_u64;
 +    let mut a_u64: u64 = 1;
 +    a_u64 %= 2;
 +
 +    let a_u128: u128 = 17;
 +    let b_u128: u128 = 3;
 +    a_u128 % b_u128;
 +    let mut a_u128: u128 = 1;
 +    a_u128 %= 2;
 +
 +    let a_usize: usize = 17;
 +    let b_usize: usize = 3;
 +    a_usize % b_usize;
 +    let mut a_usize: usize = 1;
 +    a_usize %= 2;
 +}
index e863b838699e9dc5a3a61a97490ddd162de16944,0000000000000000000000000000000000000000..f71adf5b0d014f3f640e51bdc3d7e87595a34c5a
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,156 @@@
-   --> $DIR/modulo_arithmetic_integral.rs:15:5
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:16:5
++  --> $DIR/modulo_arithmetic_integral.rs:8:5
 +   |
 +LL |     a % b;
 +   |     ^^^^^
 +   |
 +   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:17:5
++  --> $DIR/modulo_arithmetic_integral.rs:9:5
 +   |
 +LL |     b % a;
 +   |     ^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:21:5
++  --> $DIR/modulo_arithmetic_integral.rs:10:5
 +   |
 +LL |     b %= a;
 +   |     ^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:22:5
++  --> $DIR/modulo_arithmetic_integral.rs:14:5
 +   |
 +LL |     a_i8 % b_i8;
 +   |     ^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:26:5
++  --> $DIR/modulo_arithmetic_integral.rs:15:5
 +   |
 +LL |     b_i8 %= a_i8;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:27:5
++  --> $DIR/modulo_arithmetic_integral.rs:19:5
 +   |
 +LL |     a_i16 % b_i16;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:31:5
++  --> $DIR/modulo_arithmetic_integral.rs:20:5
 +   |
 +LL |     b_i16 %= a_i16;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:32:5
++  --> $DIR/modulo_arithmetic_integral.rs:24:5
 +   |
 +LL |     a_i32 % b_i32;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:36:5
++  --> $DIR/modulo_arithmetic_integral.rs:25:5
 +   |
 +LL |     b_i32 %= a_i32;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:37:5
++  --> $DIR/modulo_arithmetic_integral.rs:29:5
 +   |
 +LL |     a_i64 % b_i64;
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:41:5
++  --> $DIR/modulo_arithmetic_integral.rs:30:5
 +   |
 +LL |     b_i64 %= a_i64;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:42:5
++  --> $DIR/modulo_arithmetic_integral.rs:34:5
 +   |
 +LL |     a_i128 % b_i128;
 +   |     ^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:46:5
++  --> $DIR/modulo_arithmetic_integral.rs:35:5
 +   |
 +LL |     b_i128 %= a_i128;
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:47:5
++  --> $DIR/modulo_arithmetic_integral.rs:39:5
 +   |
 +LL |     a_isize % b_isize;
 +   |     ^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:51:5
++  --> $DIR/modulo_arithmetic_integral.rs:40:5
 +   |
 +LL |     b_isize %= a_isize;
 +   |     ^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
-   --> $DIR/modulo_arithmetic_integral.rs:52:5
++  --> $DIR/modulo_arithmetic_integral.rs:44:5
 +   |
 +LL |     a % b;
 +   |     ^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on types that might have different signs
++  --> $DIR/modulo_arithmetic_integral.rs:45:5
 +   |
 +LL |     b %= a;
 +   |     ^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: aborting due to 17 previous errors
 +
index 57a96692c0097fb26d32857cf53ba75a412ed72e,0000000000000000000000000000000000000000..047a29fa1e327201d12847ff71452f51cea4ec9d
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,37 @@@
- #![allow(
-     unused,
-     clippy::shadow_reuse,
-     clippy::shadow_unrelated,
-     clippy::no_effect,
-     clippy::unnecessary_operation,
-     clippy::modulo_one
- )]
 +#![warn(clippy::modulo_arithmetic)]
++#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
 +
 +fn main() {
 +    // Lint when both sides are const and of the opposite sign
 +    -1 % 2;
 +    1 % -2;
 +    (1 - 2) % (1 + 2);
 +    (1 + 2) % (1 - 2);
 +    35 * (7 - 4 * 2) % (-500 * -600);
 +
 +    -1i8 % 2i8;
 +    1i8 % -2i8;
 +    -1i16 % 2i16;
 +    1i16 % -2i16;
 +    -1i32 % 2i32;
 +    1i32 % -2i32;
 +    -1i64 % 2i64;
 +    1i64 % -2i64;
 +    -1i128 % 2i128;
 +    1i128 % -2i128;
 +    -1isize % 2isize;
 +    1isize % -2isize;
 +
 +    // No lint when both sides are const and of the same sign
 +    1 % 2;
 +    -1 % -2;
 +    (1 + 2) % (-1 + 2);
 +    (-1 - 2) % (1 - 2);
 +
 +    1u8 % 2u8;
 +    1u16 % 2u16;
 +    1u32 % 2u32;
 +    1u64 % 2u64;
 +    1u128 % 2u128;
 +    1usize % 2usize;
 +}
index de328bb75fe9160e7811f6f2f26a72e9333297c9,0000000000000000000000000000000000000000..64335f35f0f82d997a2b4e1e14f52fa9af68df28
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,156 @@@
-   --> $DIR/modulo_arithmetic_integral_const.rs:13:5
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:14:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:6:5
 +   |
 +LL |     -1 % 2;
 +   |     ^^^^^^
 +   |
 +   = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:15:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:7:5
 +   |
 +LL |     1 % -2;
 +   |     ^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 3`
-   --> $DIR/modulo_arithmetic_integral_const.rs:16:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:8:5
 +   |
 +LL |     (1 - 2) % (1 + 2);
 +   |     ^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `3 % -1`
-   --> $DIR/modulo_arithmetic_integral_const.rs:17:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:9:5
 +   |
 +LL |     (1 + 2) % (1 - 2);
 +   |     ^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-35 % 300000`
-   --> $DIR/modulo_arithmetic_integral_const.rs:19:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:10:5
 +   |
 +LL |     35 * (7 - 4 * 2) % (-500 * -600);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:20:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:12:5
 +   |
 +LL |     -1i8 % 2i8;
 +   |     ^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:21:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:13:5
 +   |
 +LL |     1i8 % -2i8;
 +   |     ^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:22:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:14:5
 +   |
 +LL |     -1i16 % 2i16;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:23:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:15:5
 +   |
 +LL |     1i16 % -2i16;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:24:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:16:5
 +   |
 +LL |     -1i32 % 2i32;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:25:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:17:5
 +   |
 +LL |     1i32 % -2i32;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:26:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:18:5
 +   |
 +LL |     -1i64 % 2i64;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:27:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:19:5
 +   |
 +LL |     1i64 % -2i64;
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:28:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:20:5
 +   |
 +LL |     -1i128 % 2i128;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:29:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:21:5
 +   |
 +LL |     1i128 % -2i128;
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:30:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:22:5
 +   |
 +LL |     -1isize % 2isize;
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: you are using modulo operator on constants with different signs: `1 % -2`
++  --> $DIR/modulo_arithmetic_integral_const.rs:23:5
 +   |
 +LL |     1isize % -2isize;
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: double check for expected result especially when interoperating with different languages
 +   = note: or consider using `rem_euclid` or similar function
 +
 +error: aborting due to 17 previous errors
 +
index 639eac8b8b315a0f3ec2e71f09f03ac185553b04,0000000000000000000000000000000000000000..a2e3988daff1bdc41d38db637a331abf9721c987
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,100 @@@
 +// run-rustfix
 +
 +#![warn(clippy::needless_bool)]
 +#![allow(
 +    unused,
 +    dead_code,
 +    clippy::no_effect,
 +    clippy::if_same_then_else,
++    clippy::equatable_if_let,
 +    clippy::needless_return,
 +    clippy::self_named_constructors
 +)]
 +
 +use std::cell::Cell;
 +
 +macro_rules! bool_comparison_trigger {
 +    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
 +
 +        #[derive(Clone)]
 +        pub struct Trigger {
 +            $($i: (Cell<bool>, bool, bool)),+
 +        }
 +
 +        #[allow(dead_code)]
 +        impl Trigger {
 +            pub fn trigger(&self, key: &str) -> bool {
 +                $(
 +                    if let stringify!($i) = key {
 +                        return self.$i.1 && self.$i.2 == $def;
 +                    }
 +                 )+
 +                false
 +            }
 +        }
 +    )
 +}
 +
 +fn main() {
 +    let x = true;
 +    let y = false;
 +    x;
 +    !x;
 +    !(x && y);
 +    if x {
 +        x
 +    } else {
 +        false
 +    }; // would also be questionable, but we don't catch this yet
 +    bool_ret3(x);
 +    bool_ret4(x);
 +    bool_ret5(x, x);
 +    bool_ret6(x, x);
 +    needless_bool(x);
 +    needless_bool2(x);
 +    needless_bool3(x);
 +}
 +
 +fn bool_ret3(x: bool) -> bool {
 +    return x;
 +}
 +
 +fn bool_ret4(x: bool) -> bool {
 +    return !x;
 +}
 +
 +fn bool_ret5(x: bool, y: bool) -> bool {
 +    return x && y;
 +}
 +
 +fn bool_ret6(x: bool, y: bool) -> bool {
 +    return !(x && y);
 +}
 +
 +fn needless_bool(x: bool) {
 +    if x {};
 +}
 +
 +fn needless_bool2(x: bool) {
 +    if !x {};
 +}
 +
 +fn needless_bool3(x: bool) {
 +    bool_comparison_trigger! {
 +        test_one:   false, false;
 +        test_three: false, false;
 +        test_two:   true, true;
 +    }
 +
 +    if x {};
 +    if !x {};
 +}
 +
 +fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
 +    let b = false;
 +    let returns_bool = || false;
 +
 +    let x = if b {
 +        true
 +    } else { !returns_bool() };
 +}
index a3ce086a1c90aa3a26f2af6f59a3a1e8cda24c77,0000000000000000000000000000000000000000..75805e85789194dbde588fb70e85d7f487d4d16b
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,132 @@@
 +// run-rustfix
 +
 +#![warn(clippy::needless_bool)]
 +#![allow(
 +    unused,
 +    dead_code,
 +    clippy::no_effect,
 +    clippy::if_same_then_else,
++    clippy::equatable_if_let,
 +    clippy::needless_return,
 +    clippy::self_named_constructors
 +)]
 +
 +use std::cell::Cell;
 +
 +macro_rules! bool_comparison_trigger {
 +    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
 +
 +        #[derive(Clone)]
 +        pub struct Trigger {
 +            $($i: (Cell<bool>, bool, bool)),+
 +        }
 +
 +        #[allow(dead_code)]
 +        impl Trigger {
 +            pub fn trigger(&self, key: &str) -> bool {
 +                $(
 +                    if let stringify!($i) = key {
 +                        return self.$i.1 && self.$i.2 == $def;
 +                    }
 +                 )+
 +                false
 +            }
 +        }
 +    )
 +}
 +
 +fn main() {
 +    let x = true;
 +    let y = false;
 +    if x {
 +        true
 +    } else {
 +        false
 +    };
 +    if x {
 +        false
 +    } else {
 +        true
 +    };
 +    if x && y {
 +        false
 +    } else {
 +        true
 +    };
 +    if x {
 +        x
 +    } else {
 +        false
 +    }; // would also be questionable, but we don't catch this yet
 +    bool_ret3(x);
 +    bool_ret4(x);
 +    bool_ret5(x, x);
 +    bool_ret6(x, x);
 +    needless_bool(x);
 +    needless_bool2(x);
 +    needless_bool3(x);
 +}
 +
 +fn bool_ret3(x: bool) -> bool {
 +    if x {
 +        return true;
 +    } else {
 +        return false;
 +    };
 +}
 +
 +fn bool_ret4(x: bool) -> bool {
 +    if x {
 +        return false;
 +    } else {
 +        return true;
 +    };
 +}
 +
 +fn bool_ret5(x: bool, y: bool) -> bool {
 +    if x && y {
 +        return true;
 +    } else {
 +        return false;
 +    };
 +}
 +
 +fn bool_ret6(x: bool, y: bool) -> bool {
 +    if x && y {
 +        return false;
 +    } else {
 +        return true;
 +    };
 +}
 +
 +fn needless_bool(x: bool) {
 +    if x == true {};
 +}
 +
 +fn needless_bool2(x: bool) {
 +    if x == false {};
 +}
 +
 +fn needless_bool3(x: bool) {
 +    bool_comparison_trigger! {
 +        test_one:   false, false;
 +        test_three: false, false;
 +        test_two:   true, true;
 +    }
 +
 +    if x == true {};
 +    if x == false {};
 +}
 +
 +fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
 +    let b = false;
 +    let returns_bool = || false;
 +
 +    let x = if b {
 +        true
 +    } else if returns_bool() {
 +        false
 +    } else {
 +        true
 +    };
 +}
index 8026d643c44882c476a9d8a9cfd059aa4ab389e9,0000000000000000000000000000000000000000..1fa12add16739df015d536a9a49c242450473809
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,111 @@@
-   --> $DIR/fixable.rs:40:5
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:45:5
++  --> $DIR/fixable.rs:41:5
 +   |
 +LL | /     if x {
 +LL | |         true
 +LL | |     } else {
 +LL | |         false
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `x`
 +   |
 +   = note: `-D clippy::needless-bool` implied by `-D warnings`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:50:5
++  --> $DIR/fixable.rs:46:5
 +   |
 +LL | /     if x {
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `!x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:70:5
++  --> $DIR/fixable.rs:51:5
 +   |
 +LL | /     if x && y {
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `!(x && y)`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:78:5
++  --> $DIR/fixable.rs:71:5
 +   |
 +LL | /     if x {
 +LL | |         return true;
 +LL | |     } else {
 +LL | |         return false;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:86:5
++  --> $DIR/fixable.rs:79:5
 +   |
 +LL | /     if x {
 +LL | |         return false;
 +LL | |     } else {
 +LL | |         return true;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return !x`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:94:5
++  --> $DIR/fixable.rs:87:5
 +   |
 +LL | /     if x && y {
 +LL | |         return true;
 +LL | |     } else {
 +LL | |         return false;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return x && y`
 +
 +error: this if-then-else expression returns a bool literal
-   --> $DIR/fixable.rs:102:8
++  --> $DIR/fixable.rs:95:5
 +   |
 +LL | /     if x && y {
 +LL | |         return false;
 +LL | |     } else {
 +LL | |         return true;
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `return !(x && y)`
 +
 +error: equality checks against true are unnecessary
-   --> $DIR/fixable.rs:106:8
++  --> $DIR/fixable.rs:103:8
 +   |
 +LL |     if x == true {};
 +   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 +   |
 +   = note: `-D clippy::bool-comparison` implied by `-D warnings`
 +
 +error: equality checks against false can be replaced by a negation
-   --> $DIR/fixable.rs:116:8
++  --> $DIR/fixable.rs:107:8
 +   |
 +LL |     if x == false {};
 +   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 +
 +error: equality checks against true are unnecessary
-   --> $DIR/fixable.rs:117:8
++  --> $DIR/fixable.rs:117:8
 +   |
 +LL |     if x == true {};
 +   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 +
 +error: equality checks against false can be replaced by a negation
-   --> $DIR/fixable.rs:126:12
++  --> $DIR/fixable.rs:118:8
 +   |
 +LL |     if x == false {};
 +   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 +
 +error: this if-then-else expression returns a bool literal
++  --> $DIR/fixable.rs:127:12
 +   |
 +LL |       } else if returns_bool() {
 +   |  ____________^
 +LL | |         false
 +LL | |     } else {
 +LL | |         true
 +LL | |     };
 +   | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 +
 +error: aborting due to 12 previous errors
 +
index 37efa6274df7aa904b65fc99b458ad60acc4dfef,0000000000000000000000000000000000000000..9c999e12b4cbc4c6d5a3afed29e97cffa3638623
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,215 @@@
- #![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)]
 +// run-rustfix
 +// edition:2018
 +
 +#![feature(let_else)]
 +#![allow(unused)]
++#![allow(
++    clippy::if_same_then_else,
++    clippy::single_match,
++    clippy::needless_bool,
++    clippy::equatable_if_let
++)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    true
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => {},
 +    }
 +}
 +
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| {})
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            
 +        };
 +        let _ = || {};
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    true
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => {},
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index cbf384ac9e4356a21548e5181947da79a0b95ad2,0000000000000000000000000000000000000000..da7dcf4f0a9ea377596a830996947f6d5afa60fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,215 @@@
- #![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)]
 +// run-rustfix
 +// edition:2018
 +
 +#![feature(let_else)]
 +#![allow(unused)]
++#![allow(
++    clippy::if_same_then_else,
++    clippy::single_match,
++    clippy::needless_bool,
++    clippy::equatable_if_let
++)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    return;
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| return)
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            return;
 +        };
 +        let _ = || return;
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| return Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    return;
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index 7ce7028bbae4b1defd812911afb7a4a540d8b7fe,0000000000000000000000000000000000000000..2e802cff1e686917ddef5a3c5e1ba7421c617ec4
mode 100644,000000..100644
--- /dev/null
@@@ -1,196 -1,0 +1,196 @@@
-   --> $DIR/needless_return.rs:20:5
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:24:5
++  --> $DIR/needless_return.rs:25: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:29:9
++  --> $DIR/needless_return.rs:29:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:31:9
++  --> $DIR/needless_return.rs:34:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:37:17
++  --> $DIR/needless_return.rs:36:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:39:13
++  --> $DIR/needless_return.rs:42:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:46:9
++  --> $DIR/needless_return.rs:44:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:48:16
++  --> $DIR/needless_return.rs:51:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:56:5
++  --> $DIR/needless_return.rs:53:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:61:9
++  --> $DIR/needless_return.rs:61:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:63:9
++  --> $DIR/needless_return.rs:66:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:70:14
++  --> $DIR/needless_return.rs:68:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:85:9
++  --> $DIR/needless_return.rs:75:14
 +   |
 +LL |         _ => return,
 +   |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:87:9
++  --> $DIR/needless_return.rs:90:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:108:32
++  --> $DIR/needless_return.rs:92:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:113:13
++  --> $DIR/needless_return.rs:113:32
 +   |
 +LL |         bar.unwrap_or_else(|_| return)
 +   |                                ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:115:20
++  --> $DIR/needless_return.rs:118:13
 +   |
 +LL |             return;
 +   |             ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:121:32
++  --> $DIR/needless_return.rs:120:20
 +   |
 +LL |         let _ = || return;
 +   |                    ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:130:5
++  --> $DIR/needless_return.rs:126:32
 +   |
 +LL |         res.unwrap_or_else(|_| return Foo)
 +   |                                ^^^^^^^^^^ help: remove `return`: `Foo`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:134:5
++  --> $DIR/needless_return.rs:135:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:139:9
++  --> $DIR/needless_return.rs:139:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:141:9
++  --> $DIR/needless_return.rs:144:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:147:17
++  --> $DIR/needless_return.rs:146:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:149:13
++  --> $DIR/needless_return.rs:152:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:156:9
++  --> $DIR/needless_return.rs:154:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:158:16
++  --> $DIR/needless_return.rs:161:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:166:5
++  --> $DIR/needless_return.rs:163:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:171:9
++  --> $DIR/needless_return.rs:171:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:173:9
++  --> $DIR/needless_return.rs:176:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:180:14
++  --> $DIR/needless_return.rs:178:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:195:9
++  --> $DIR/needless_return.rs:185:14
 +   |
 +LL |         _ => return,
 +   |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:197:9
++  --> $DIR/needless_return.rs:200:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
++  --> $DIR/needless_return.rs:202:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
 +error: aborting due to 32 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..eca7f5e5655913785f3e98cf94d3a179549e74ba
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,127 @@@
++#![warn(clippy::non_send_fields_in_send_ty)]
++#![feature(extern_types)]
++
++use std::cell::UnsafeCell;
++use std::ptr::NonNull;
++use std::rc::Rc;
++use std::sync::{Arc, Mutex, MutexGuard};
++
++// disrustor / RUSTSEC-2020-0150
++pub struct RingBuffer<T> {
++    data: Vec<UnsafeCell<T>>,
++    capacity: usize,
++    mask: usize,
++}
++
++unsafe impl<T> Send for RingBuffer<T> {}
++
++// noise_search / RUSTSEC-2020-0141
++pub struct MvccRwLock<T> {
++    raw: *const T,
++    lock: Mutex<Box<T>>,
++}
++
++unsafe impl<T> Send for MvccRwLock<T> {}
++
++// async-coap / RUSTSEC-2020-0124
++pub struct ArcGuard<RC, T> {
++    inner: T,
++    head: Arc<RC>,
++}
++
++unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
++
++// rusb / RUSTSEC-2020-0098
++extern "C" {
++    type libusb_device_handle;
++}
++
++pub trait UsbContext {
++    // some user trait that does not guarantee `Send`
++}
++
++pub struct DeviceHandle<T: UsbContext> {
++    context: T,
++    handle: NonNull<libusb_device_handle>,
++}
++
++unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
++
++// Other basic tests
++pub struct NoGeneric {
++    rc_is_not_send: Rc<String>,
++}
++
++unsafe impl Send for NoGeneric {}
++
++pub struct MultiField<T> {
++    field1: T,
++    field2: T,
++    field3: T,
++}
++
++unsafe impl<T> Send for MultiField<T> {}
++
++pub enum MyOption<T> {
++    MySome(T),
++    MyNone,
++}
++
++unsafe impl<T> Send for MyOption<T> {}
++
++// Multiple type parameters
++pub struct MultiParam<A, B> {
++    vec: Vec<(A, B)>,
++}
++
++unsafe impl<A, B> Send for MultiParam<A, B> {}
++
++// Tests for raw pointer heuristic
++extern "C" {
++    type NonSend;
++}
++
++pub struct HeuristicTest {
++    // raw pointers are allowed
++    field1: Vec<*const NonSend>,
++    field2: [*const NonSend; 3],
++    field3: (*const NonSend, *const NonSend, *const NonSend),
++    // not allowed when it contains concrete `!Send` field
++    field4: (*const NonSend, Rc<u8>),
++    // nested raw pointer is also allowed
++    field5: Vec<Vec<*const NonSend>>,
++}
++
++unsafe impl Send for HeuristicTest {}
++
++// Test attributes
++#[allow(clippy::non_send_fields_in_send_ty)]
++pub struct AttrTest1<T>(T);
++
++pub struct AttrTest2<T> {
++    #[allow(clippy::non_send_fields_in_send_ty)]
++    field: T,
++}
++
++pub enum AttrTest3<T> {
++    #[allow(clippy::non_send_fields_in_send_ty)]
++    Enum1(T),
++    Enum2(T),
++}
++
++unsafe impl<T> Send for AttrTest1<T> {}
++unsafe impl<T> Send for AttrTest2<T> {}
++unsafe impl<T> Send for AttrTest3<T> {}
++
++// Multiple non-overlapping `Send` for a single type
++pub struct Complex<A, B> {
++    field1: A,
++    field2: B,
++}
++
++unsafe impl<P> Send for Complex<P, u32> {}
++
++// `MutexGuard` is non-Send
++unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8b8a1d16d9bb96172bd747f011814853230725b9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,171 @@@
++error: this implementation is unsound, as some fields in `RingBuffer<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:16:1
++   |
++LL | unsafe impl<T> Send for RingBuffer<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++   = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
++note: the type of field `data` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:11:5
++   |
++LL |     data: Vec<UnsafeCell<T>>,
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send`
++
++error: this implementation is unsound, as some fields in `MvccRwLock<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:24:1
++   |
++LL | unsafe impl<T> Send for MvccRwLock<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `lock` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:21:5
++   |
++LL |     lock: Mutex<Box<T>>,
++   |     ^^^^^^^^^^^^^^^^^^^
++   = help: add bounds on type parameter `T` that satisfy `Mutex<Box<T>>: Send`
++
++error: this implementation is unsound, as some fields in `ArcGuard<RC, T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:32:1
++   |
++LL | unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `head` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:29:5
++   |
++LL |     head: Arc<RC>,
++   |     ^^^^^^^^^^^^^
++   = help: add bounds on type parameter `RC` that satisfy `Arc<RC>: Send`
++
++error: this implementation is unsound, as some fields in `DeviceHandle<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:48:1
++   |
++LL | unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `context` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:44:5
++   |
++LL |     context: T,
++   |     ^^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:55:1
++   |
++LL | unsafe impl Send for NoGeneric {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `rc_is_not_send` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:52:5
++   |
++LL |     rc_is_not_send: Rc<String>,
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++
++error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:63:1
++   |
++LL | unsafe impl<T> Send for MultiField<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field1` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:58:5
++   |
++LL |     field1: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++note: the type of field `field2` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:59:5
++   |
++LL |     field2: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++note: the type of field `field3` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:60:5
++   |
++LL |     field3: T,
++   |     ^^^^^^^^^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:70:1
++   |
++LL | unsafe impl<T> Send for MyOption<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `0` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:66:12
++   |
++LL |     MySome(T),
++   |            ^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `MultiParam<A, B>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:77:1
++   |
++LL | unsafe impl<A, B> Send for MultiParam<A, B> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `vec` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:74:5
++   |
++LL |     vec: Vec<(A, B)>,
++   |     ^^^^^^^^^^^^^^^^
++   = help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send`
++
++error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:95:1
++   |
++LL | unsafe impl Send for HeuristicTest {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field4` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:90:5
++   |
++LL |     field4: (*const NonSend, Rc<u8>),
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++
++error: this implementation is unsound, as some fields in `AttrTest3<T>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:114:1
++   |
++LL | unsafe impl<T> Send for AttrTest3<T> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `0` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:109:11
++   |
++LL |     Enum2(T),
++   |           ^
++   = help: add `T: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `Complex<P, u32>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:122:1
++   |
++LL | unsafe impl<P> Send for Complex<P, u32> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field1` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:118:5
++   |
++LL |     field1: A,
++   |     ^^^^^^^^^
++   = help: add `P: Send` bound in `Send` impl
++
++error: this implementation is unsound, as some fields in `Complex<Q, MutexGuard<'static, bool>>` are `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:125:1
++   |
++LL | unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   |
++note: the type of field `field2` is `!Send`
++  --> $DIR/non_send_fields_in_send_ty.rs:119:5
++   |
++LL |     field2: B,
++   |     ^^^^^^^^^
++   = help: use a thread-safe type that implements `Send`
++
++error: aborting due to 12 previous errors
++
index d1815d0aec331692f66945f584d298fdb9e8d839,0000000000000000000000000000000000000000..a3ebe5d0703846bd09a131d94a0008700eba1b9c
mode 100644,000000..100644
--- /dev/null
@@@ -1,151 -1,0 +1,151 @@@
- #![allow(clippy::ref_option_ref)]
 +// edition:2018
 +// run-rustfix
 +#![warn(clippy::option_if_let_else)]
 +#![allow(clippy::redundant_closure)]
++#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
 +
 +fn bad1(string: Option<&str>) -> (bool, &str) {
 +    string.map_or((false, "hello"), |x| (true, x))
 +}
 +
 +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
 +    if string.is_none() {
 +        None
 +    } else if let Some(x) = string {
 +        Some((true, x))
 +    } else {
 +        Some((false, ""))
 +    }
 +}
 +
 +fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
 +    let _ = string.map_or(0, |s| s.len());
 +    let _ = num.as_ref().map_or(&0, |s| s);
 +    let _ = num.as_mut().map_or(&mut 0, |s| {
 +        *s += 1;
 +        s
 +    });
 +    let _ = num.as_ref().map_or(&0, |s| s);
 +    let _ = num.map_or(0, |mut s| {
 +        s += 1;
 +        s
 +    });
 +    let _ = num.as_mut().map_or(&mut 0, |s| {
 +        *s += 1;
 +        s
 +    });
 +}
 +
 +fn longer_body(arg: Option<u32>) -> u32 {
 +    arg.map_or(13, |x| {
 +        let y = x * x;
 +        y * y
 +    })
 +}
 +
 +fn impure_else(arg: Option<i32>) {
 +    let side_effect = || {
 +        println!("return 1");
 +        1
 +    };
 +    let _ = arg.map_or_else(|| side_effect(), |x| x);
 +}
 +
 +fn test_map_or_else(arg: Option<u32>) {
 +    let _ = arg.map_or_else(|| {
 +        let mut y = 1;
 +        y = (y + 2 / y) / 2;
 +        y = (y + 2 / y) / 2;
 +        y
 +    }, |x| x * x * x * x);
 +}
 +
 +fn negative_tests(arg: Option<u32>) -> u32 {
 +    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
 +    for _ in 0..10 {
 +        let _ = if let Some(x) = arg {
 +            x
 +        } else {
 +            continue;
 +        };
 +    }
 +    let _ = if let Some(x) = arg {
 +        return x;
 +    } else {
 +        5
 +    };
 +    7
 +}
 +
 +fn main() {
 +    let optional = Some(5);
 +    let _ = optional.map_or(5, |x| x + 2);
 +    let _ = bad1(None);
 +    let _ = else_if_option(None);
 +    unop_bad(&None, None);
 +    let _ = longer_body(None);
 +    test_map_or_else(None);
 +    let _ = negative_tests(None);
 +    let _ = impure_else(None);
 +
 +    let _ = Some(0).map_or(0, |x| loop {
 +            if x == 0 {
 +                break x;
 +            }
 +        });
 +
 +    // #7576
 +    const fn _f(x: Option<u32>) -> u32 {
 +        // Don't lint, `map_or` isn't const
 +        if let Some(x) = x { x } else { 10 }
 +    }
 +
 +    // #5822
 +    let s = String::new();
 +    // Don't lint, `Some` branch consumes `s`, but else branch uses `s`
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        s.len()
 +    };
 +
 +    let s = String::new();
 +    // Lint, both branches immutably borrow `s`.
 +    let _ = Some(0).map_or_else(|| s.len(), |x| s.len() + x);
 +
 +    let s = String::new();
 +    // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`.
 +    let _ = Some(0).map_or(1, |x| {
 +        let s = s;
 +        s.len() + x
 +    });
 +
 +    let s = Some(String::new());
 +    // Don't lint, `Some` branch borrows `s`, but else branch consumes `s`
 +    let _ = if let Some(x) = &s {
 +        x.len()
 +    } else {
 +        let _s = s;
 +        10
 +    };
 +
 +    let mut s = Some(String::new());
 +    // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows  `s`
 +    let _ = if let Some(x) = &mut s {
 +        x.push_str("test");
 +        x.len()
 +    } else {
 +        let _s = &s;
 +        10
 +    };
 +
 +    async fn _f1(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn _f2() {
 +        // Don't lint. `await` can't be moved into a closure.
 +        let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
 +    }
 +}
index a15627338cb4aaeaa8460c83d03f5e30f5c86c2d,0000000000000000000000000000000000000000..b11df3db60f57edfa56913f4af239b343259ecfa
mode 100644,000000..100644
--- /dev/null
@@@ -1,176 -1,0 +1,176 @@@
- #![allow(clippy::ref_option_ref)]
 +// edition:2018
 +// run-rustfix
 +#![warn(clippy::option_if_let_else)]
 +#![allow(clippy::redundant_closure)]
++#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
 +
 +fn bad1(string: Option<&str>) -> (bool, &str) {
 +    if let Some(x) = string {
 +        (true, x)
 +    } else {
 +        (false, "hello")
 +    }
 +}
 +
 +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
 +    if string.is_none() {
 +        None
 +    } else if let Some(x) = string {
 +        Some((true, x))
 +    } else {
 +        Some((false, ""))
 +    }
 +}
 +
 +fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
 +    let _ = if let Some(s) = *string { s.len() } else { 0 };
 +    let _ = if let Some(s) = &num { s } else { &0 };
 +    let _ = if let Some(s) = &mut num {
 +        *s += 1;
 +        s
 +    } else {
 +        &mut 0
 +    };
 +    let _ = if let Some(ref s) = num { s } else { &0 };
 +    let _ = if let Some(mut s) = num {
 +        s += 1;
 +        s
 +    } else {
 +        0
 +    };
 +    let _ = if let Some(ref mut s) = num {
 +        *s += 1;
 +        s
 +    } else {
 +        &mut 0
 +    };
 +}
 +
 +fn longer_body(arg: Option<u32>) -> u32 {
 +    if let Some(x) = arg {
 +        let y = x * x;
 +        y * y
 +    } else {
 +        13
 +    }
 +}
 +
 +fn impure_else(arg: Option<i32>) {
 +    let side_effect = || {
 +        println!("return 1");
 +        1
 +    };
 +    let _ = if let Some(x) = arg {
 +        x
 +    } else {
 +        // map_or_else must be suggested
 +        side_effect()
 +    };
 +}
 +
 +fn test_map_or_else(arg: Option<u32>) {
 +    let _ = if let Some(x) = arg {
 +        x * x * x * x
 +    } else {
 +        let mut y = 1;
 +        y = (y + 2 / y) / 2;
 +        y = (y + 2 / y) / 2;
 +        y
 +    };
 +}
 +
 +fn negative_tests(arg: Option<u32>) -> u32 {
 +    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
 +    for _ in 0..10 {
 +        let _ = if let Some(x) = arg {
 +            x
 +        } else {
 +            continue;
 +        };
 +    }
 +    let _ = if let Some(x) = arg {
 +        return x;
 +    } else {
 +        5
 +    };
 +    7
 +}
 +
 +fn main() {
 +    let optional = Some(5);
 +    let _ = if let Some(x) = optional { x + 2 } else { 5 };
 +    let _ = bad1(None);
 +    let _ = else_if_option(None);
 +    unop_bad(&None, None);
 +    let _ = longer_body(None);
 +    test_map_or_else(None);
 +    let _ = negative_tests(None);
 +    let _ = impure_else(None);
 +
 +    let _ = if let Some(x) = Some(0) {
 +        loop {
 +            if x == 0 {
 +                break x;
 +            }
 +        }
 +    } else {
 +        0
 +    };
 +
 +    // #7576
 +    const fn _f(x: Option<u32>) -> u32 {
 +        // Don't lint, `map_or` isn't const
 +        if let Some(x) = x { x } else { 10 }
 +    }
 +
 +    // #5822
 +    let s = String::new();
 +    // Don't lint, `Some` branch consumes `s`, but else branch uses `s`
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        s.len()
 +    };
 +
 +    let s = String::new();
 +    // Lint, both branches immutably borrow `s`.
 +    let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
 +
 +    let s = String::new();
 +    // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`.
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        1
 +    };
 +
 +    let s = Some(String::new());
 +    // Don't lint, `Some` branch borrows `s`, but else branch consumes `s`
 +    let _ = if let Some(x) = &s {
 +        x.len()
 +    } else {
 +        let _s = s;
 +        10
 +    };
 +
 +    let mut s = Some(String::new());
 +    // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows  `s`
 +    let _ = if let Some(x) = &mut s {
 +        x.push_str("test");
 +        x.len()
 +    } else {
 +        let _s = &s;
 +        10
 +    };
 +
 +    async fn _f1(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn _f2() {
 +        // Don't lint. `await` can't be moved into a closure.
 +        let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
 +    }
 +}
index 794ed542435d149910e44c4ecf712185b7df2355,0000000000000000000000000000000000000000..ce3229f17591e472251795bd1cd24646ead95a5b
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- #![allow(clippy::if_same_then_else)]
 +// run-rustfix
 +
 +// Issue #5746
 +#![warn(clippy::redundant_pattern_matching)]
++#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
 +use std::task::Poll::{Pending, Ready};
 +
 +fn main() {
 +    let m = std::sync::Mutex::new((0, 0));
 +
 +    // Result
 +    if m.lock().is_ok() {}
 +    if Err::<(), _>(m.lock().unwrap().0).is_err() {}
 +
 +    {
 +        if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {}
 +    }
 +    if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {
 +    } else {
 +    }
 +    if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {}
 +    if Err::<std::sync::MutexGuard<()>, _>(()).is_err() {}
 +
 +    if Ok::<_, ()>(String::new()).is_ok() {}
 +    if Err::<(), _>((String::new(), ())).is_err() {}
 +
 +    // Option
 +    if Some(m.lock()).is_some() {}
 +    if Some(m.lock().unwrap().0).is_some() {}
 +
 +    {
 +        if None::<std::sync::MutexGuard<()>>.is_none() {}
 +    }
 +    if None::<std::sync::MutexGuard<()>>.is_none() {
 +    } else {
 +    }
 +
 +    if None::<std::sync::MutexGuard<()>>.is_none() {}
 +
 +    if Some(String::new()).is_some() {}
 +    if Some((String::new(), ())).is_some() {}
 +
 +    // Poll
 +    if Ready(m.lock()).is_ready() {}
 +    if Ready(m.lock().unwrap().0).is_ready() {}
 +
 +    {
 +        if Pending::<std::sync::MutexGuard<()>>.is_pending() {}
 +    }
 +    if Pending::<std::sync::MutexGuard<()>>.is_pending() {
 +    } else {
 +    }
 +
 +    if Pending::<std::sync::MutexGuard<()>>.is_pending() {}
 +
 +    if Ready(String::new()).is_ready() {}
 +    if Ready((String::new(), ())).is_ready() {}
 +}
index b9c82d86f618b4041f6bb568d52e2d652e4934be,0000000000000000000000000000000000000000..29b8543cf473a92241c7db8a2586922f966452a6
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
- #![allow(clippy::if_same_then_else)]
 +// run-rustfix
 +
 +// Issue #5746
 +#![warn(clippy::redundant_pattern_matching)]
++#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
 +use std::task::Poll::{Pending, Ready};
 +
 +fn main() {
 +    let m = std::sync::Mutex::new((0, 0));
 +
 +    // Result
 +    if let Ok(_) = m.lock() {}
 +    if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {}
 +
 +    {
 +        if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {}
 +    }
 +    if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {
 +    } else {
 +    }
 +    if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {}
 +    if let Err(_) = Err::<std::sync::MutexGuard<()>, _>(()) {}
 +
 +    if let Ok(_) = Ok::<_, ()>(String::new()) {}
 +    if let Err(_) = Err::<(), _>((String::new(), ())) {}
 +
 +    // Option
 +    if let Some(_) = Some(m.lock()) {}
 +    if let Some(_) = Some(m.lock().unwrap().0) {}
 +
 +    {
 +        if let None = None::<std::sync::MutexGuard<()>> {}
 +    }
 +    if let None = None::<std::sync::MutexGuard<()>> {
 +    } else {
 +    }
 +
 +    if let None = None::<std::sync::MutexGuard<()>> {}
 +
 +    if let Some(_) = Some(String::new()) {}
 +    if let Some(_) = Some((String::new(), ())) {}
 +
 +    // Poll
 +    if let Ready(_) = Ready(m.lock()) {}
 +    if let Ready(_) = Ready(m.lock().unwrap().0) {}
 +
 +    {
 +        if let Pending = Pending::<std::sync::MutexGuard<()>> {}
 +    }
 +    if let Pending = Pending::<std::sync::MutexGuard<()>> {
 +    } else {
 +    }
 +
 +    if let Pending = Pending::<std::sync::MutexGuard<()>> {}
 +
 +    if let Ready(_) = Ready(String::new()) {}
 +    if let Ready(_) = Ready((String::new(), ())) {}
 +}
index 997144772669be4fdabd45a0834deebf1c8c3388,0000000000000000000000000000000000000000..813e268a60c3debe1b49c4a4b4e81bad6f5b4f7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,82 @@@
 +// run-rustfix
 +
 +#![warn(clippy::all)]
 +#![warn(clippy::redundant_pattern_matching)]
 +#![allow(
 +    unused_must_use,
 +    clippy::needless_bool,
 +    clippy::match_like_matches_macro,
++    clippy::equatable_if_let,
 +    clippy::if_same_then_else
 +)]
 +
 +fn main() {
 +    if None::<()>.is_none() {}
 +
 +    if Some(42).is_some() {}
 +
 +    if Some(42).is_some() {
 +        foo();
 +    } else {
 +        bar();
 +    }
 +
 +    while Some(42).is_some() {}
 +
 +    while Some(42).is_none() {}
 +
 +    while None::<()>.is_none() {}
 +
 +    let mut v = vec![1, 2, 3];
 +    while v.pop().is_some() {
 +        foo();
 +    }
 +
 +    if None::<i32>.is_none() {}
 +
 +    if Some(42).is_some() {}
 +
 +    Some(42).is_some();
 +
 +    None::<()>.is_none();
 +
 +    let _ = None::<()>.is_none();
 +
 +    let opt = Some(false);
 +    let _ = if opt.is_some() { true } else { false };
 +
 +    issue6067();
 +
 +    let _ = if gen_opt().is_some() {
 +        1
 +    } else if gen_opt().is_none() {
 +        2
 +    } else {
 +        3
 +    };
 +}
 +
 +fn gen_opt() -> Option<()> {
 +    None
 +}
 +
 +fn foo() {}
 +
 +fn bar() {}
 +
 +// Methods that are unstable const should not be suggested within a const context, see issue #5697.
 +// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
 +// so the following should be linted.
 +const fn issue6067() {
 +    if Some(42).is_some() {}
 +
 +    if None::<()>.is_none() {}
 +
 +    while Some(42).is_some() {}
 +
 +    while None::<()>.is_none() {}
 +
 +    Some(42).is_some();
 +
 +    None::<()>.is_none();
 +}
index 8309847e18162796d787c4bb771bb5ffd7f58600,0000000000000000000000000000000000000000..82a98468943dfcffc67a064be39a1a3dd4ba6f6f
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,97 @@@
 +// run-rustfix
 +
 +#![warn(clippy::all)]
 +#![warn(clippy::redundant_pattern_matching)]
 +#![allow(
 +    unused_must_use,
 +    clippy::needless_bool,
 +    clippy::match_like_matches_macro,
++    clippy::equatable_if_let,
 +    clippy::if_same_then_else
 +)]
 +
 +fn main() {
 +    if let None = None::<()> {}
 +
 +    if let Some(_) = Some(42) {}
 +
 +    if let Some(_) = Some(42) {
 +        foo();
 +    } else {
 +        bar();
 +    }
 +
 +    while let Some(_) = Some(42) {}
 +
 +    while let None = Some(42) {}
 +
 +    while let None = None::<()> {}
 +
 +    let mut v = vec![1, 2, 3];
 +    while let Some(_) = v.pop() {
 +        foo();
 +    }
 +
 +    if None::<i32>.is_none() {}
 +
 +    if Some(42).is_some() {}
 +
 +    match Some(42) {
 +        Some(_) => true,
 +        None => false,
 +    };
 +
 +    match None::<()> {
 +        Some(_) => false,
 +        None => true,
 +    };
 +
 +    let _ = match None::<()> {
 +        Some(_) => false,
 +        None => true,
 +    };
 +
 +    let opt = Some(false);
 +    let _ = if let Some(_) = opt { true } else { false };
 +
 +    issue6067();
 +
 +    let _ = if let Some(_) = gen_opt() {
 +        1
 +    } else if let None = gen_opt() {
 +        2
 +    } else {
 +        3
 +    };
 +}
 +
 +fn gen_opt() -> Option<()> {
 +    None
 +}
 +
 +fn foo() {}
 +
 +fn bar() {}
 +
 +// Methods that are unstable const should not be suggested within a const context, see issue #5697.
 +// However, in Rust 1.48.0 the methods `is_some` and `is_none` of `Option` were stabilized as const,
 +// so the following should be linted.
 +const fn issue6067() {
 +    if let Some(_) = Some(42) {}
 +
 +    if let None = None::<()> {}
 +
 +    while let Some(_) = Some(42) {}
 +
 +    while let None = None::<()> {}
 +
 +    match Some(42) {
 +        Some(_) => true,
 +        None => false,
 +    };
 +
 +    match None::<()> {
 +        Some(_) => false,
 +        None => true,
 +    };
 +}
index 613a30d4a48453bbede0d3c9f4386a7b304938a3,0000000000000000000000000000000000000000..3a58e5ad7bee96ff94202e42dc5cf99ec17928fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,134 -1,0 +1,134 @@@
-   --> $DIR/redundant_pattern_matching_option.rs:13:12
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:15:12
++  --> $DIR/redundant_pattern_matching_option.rs:14:12
 +   |
 +LL |     if let None = None::<()> {}
 +   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 +   |
 +   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:17:12
++  --> $DIR/redundant_pattern_matching_option.rs:16:12
 +   |
 +LL |     if let Some(_) = Some(42) {}
 +   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:23:15
++  --> $DIR/redundant_pattern_matching_option.rs:18:12
 +   |
 +LL |     if let Some(_) = Some(42) {
 +   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:25:15
++  --> $DIR/redundant_pattern_matching_option.rs:24:15
 +   |
 +LL |     while let Some(_) = Some(42) {}
 +   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:27:15
++  --> $DIR/redundant_pattern_matching_option.rs:26:15
 +   |
 +LL |     while let None = Some(42) {}
 +   |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:30:15
++  --> $DIR/redundant_pattern_matching_option.rs:28:15
 +   |
 +LL |     while let None = None::<()> {}
 +   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:38:5
++  --> $DIR/redundant_pattern_matching_option.rs:31:15
 +   |
 +LL |     while let Some(_) = v.pop() {
 +   |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:43:5
++  --> $DIR/redundant_pattern_matching_option.rs:39:5
 +   |
 +LL | /     match Some(42) {
 +LL | |         Some(_) => true,
 +LL | |         None => false,
 +LL | |     };
 +   | |_____^ help: try this: `Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:48:13
++  --> $DIR/redundant_pattern_matching_option.rs:44:5
 +   |
 +LL | /     match None::<()> {
 +LL | |         Some(_) => false,
 +LL | |         None => true,
 +LL | |     };
 +   | |_____^ help: try this: `None::<()>.is_none()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:54:20
++  --> $DIR/redundant_pattern_matching_option.rs:49:13
 +   |
 +LL |       let _ = match None::<()> {
 +   |  _____________^
 +LL | |         Some(_) => false,
 +LL | |         None => true,
 +LL | |     };
 +   | |_____^ help: try this: `None::<()>.is_none()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:58:20
++  --> $DIR/redundant_pattern_matching_option.rs:55:20
 +   |
 +LL |     let _ = if let Some(_) = opt { true } else { false };
 +   |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:60:19
++  --> $DIR/redundant_pattern_matching_option.rs:59:20
 +   |
 +LL |     let _ = if let Some(_) = gen_opt() {
 +   |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:79:12
++  --> $DIR/redundant_pattern_matching_option.rs:61:19
 +   |
 +LL |     } else if let None = gen_opt() {
 +   |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:81:12
++  --> $DIR/redundant_pattern_matching_option.rs:80:12
 +   |
 +LL |     if let Some(_) = Some(42) {}
 +   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:83:15
++  --> $DIR/redundant_pattern_matching_option.rs:82:12
 +   |
 +LL |     if let None = None::<()> {}
 +   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:85:15
++  --> $DIR/redundant_pattern_matching_option.rs:84:15
 +   |
 +LL |     while let Some(_) = Some(42) {}
 +   |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
-   --> $DIR/redundant_pattern_matching_option.rs:87:5
++  --> $DIR/redundant_pattern_matching_option.rs:86:15
 +   |
 +LL |     while let None = None::<()> {}
 +   |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 +
 +error: redundant pattern matching, consider using `is_some()`
-   --> $DIR/redundant_pattern_matching_option.rs:92:5
++  --> $DIR/redundant_pattern_matching_option.rs:88:5
 +   |
 +LL | /     match Some(42) {
 +LL | |         Some(_) => true,
 +LL | |         None => false,
 +LL | |     };
 +   | |_____^ help: try this: `Some(42).is_some()`
 +
 +error: redundant pattern matching, consider using `is_none()`
++  --> $DIR/redundant_pattern_matching_option.rs:93:5
 +   |
 +LL | /     match None::<()> {
 +LL | |         Some(_) => false,
 +LL | |         None => true,
 +LL | |     };
 +   | |_____^ help: try this: `None::<()>.is_none()`
 +
 +error: aborting due to 19 previous errors
 +
index c297745380404030beee5b4487083387349af196,0000000000000000000000000000000000000000..3645f2c4bfdd2602ce3875322b49dc8924b9635f
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,76 @@@
 +// run-rustfix
 +
 +#![warn(clippy::all)]
 +#![warn(clippy::redundant_pattern_matching)]
 +#![allow(
 +    unused_must_use,
 +    clippy::needless_bool,
 +    clippy::match_like_matches_macro,
++    clippy::equatable_if_let,
 +    clippy::if_same_then_else
 +)]
 +
 +use std::task::Poll::{self, Pending, Ready};
 +
 +fn main() {
 +    if Pending::<()>.is_pending() {}
 +
 +    if Ready(42).is_ready() {}
 +
 +    if Ready(42).is_ready() {
 +        foo();
 +    } else {
 +        bar();
 +    }
 +
 +    while Ready(42).is_ready() {}
 +
 +    while Ready(42).is_pending() {}
 +
 +    while Pending::<()>.is_pending() {}
 +
 +    if Pending::<i32>.is_pending() {}
 +
 +    if Ready(42).is_ready() {}
 +
 +    Ready(42).is_ready();
 +
 +    Pending::<()>.is_pending();
 +
 +    let _ = Pending::<()>.is_pending();
 +
 +    let poll = Ready(false);
 +    let _ = if poll.is_ready() { true } else { false };
 +
 +    poll_const();
 +
 +    let _ = if gen_poll().is_ready() {
 +        1
 +    } else if gen_poll().is_pending() {
 +        2
 +    } else {
 +        3
 +    };
 +}
 +
 +fn gen_poll() -> Poll<()> {
 +    Pending
 +}
 +
 +fn foo() {}
 +
 +fn bar() {}
 +
 +const fn poll_const() {
 +    if Ready(42).is_ready() {}
 +
 +    if Pending::<()>.is_pending() {}
 +
 +    while Ready(42).is_ready() {}
 +
 +    while Pending::<()>.is_pending() {}
 +
 +    Ready(42).is_ready();
 +
 +    Pending::<()>.is_pending();
 +}
index 665c8c417504dbb1b54b4c48e1ef39216c6d6a83,0000000000000000000000000000000000000000..866c71b7cfa8034aa6fd1409fad780d8910d4e50
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,91 @@@
 +// run-rustfix
 +
 +#![warn(clippy::all)]
 +#![warn(clippy::redundant_pattern_matching)]
 +#![allow(
 +    unused_must_use,
 +    clippy::needless_bool,
 +    clippy::match_like_matches_macro,
++    clippy::equatable_if_let,
 +    clippy::if_same_then_else
 +)]
 +
 +use std::task::Poll::{self, Pending, Ready};
 +
 +fn main() {
 +    if let Pending = Pending::<()> {}
 +
 +    if let Ready(_) = Ready(42) {}
 +
 +    if let Ready(_) = Ready(42) {
 +        foo();
 +    } else {
 +        bar();
 +    }
 +
 +    while let Ready(_) = Ready(42) {}
 +
 +    while let Pending = Ready(42) {}
 +
 +    while let Pending = Pending::<()> {}
 +
 +    if Pending::<i32>.is_pending() {}
 +
 +    if Ready(42).is_ready() {}
 +
 +    match Ready(42) {
 +        Ready(_) => true,
 +        Pending => false,
 +    };
 +
 +    match Pending::<()> {
 +        Ready(_) => false,
 +        Pending => true,
 +    };
 +
 +    let _ = match Pending::<()> {
 +        Ready(_) => false,
 +        Pending => true,
 +    };
 +
 +    let poll = Ready(false);
 +    let _ = if let Ready(_) = poll { true } else { false };
 +
 +    poll_const();
 +
 +    let _ = if let Ready(_) = gen_poll() {
 +        1
 +    } else if let Pending = gen_poll() {
 +        2
 +    } else {
 +        3
 +    };
 +}
 +
 +fn gen_poll() -> Poll<()> {
 +    Pending
 +}
 +
 +fn foo() {}
 +
 +fn bar() {}
 +
 +const fn poll_const() {
 +    if let Ready(_) = Ready(42) {}
 +
 +    if let Pending = Pending::<()> {}
 +
 +    while let Ready(_) = Ready(42) {}
 +
 +    while let Pending = Pending::<()> {}
 +
 +    match Ready(42) {
 +        Ready(_) => true,
 +        Pending => false,
 +    };
 +
 +    match Pending::<()> {
 +        Ready(_) => false,
 +        Pending => true,
 +    };
 +}
index 5ecf024a733a31a376e589f87898357995aceb97,0000000000000000000000000000000000000000..1b480f3157f7072dd9be64e1059a22c4f80d1e5f
mode 100644,000000..100644
--- /dev/null
@@@ -1,128 -1,0 +1,128 @@@
-   --> $DIR/redundant_pattern_matching_poll.rs:15:12
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:17:12
++  --> $DIR/redundant_pattern_matching_poll.rs:16:12
 +   |
 +LL |     if let Pending = Pending::<()> {}
 +   |     -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
 +   |
 +   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:19:12
++  --> $DIR/redundant_pattern_matching_poll.rs:18:12
 +   |
 +LL |     if let Ready(_) = Ready(42) {}
 +   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:25:15
++  --> $DIR/redundant_pattern_matching_poll.rs:20:12
 +   |
 +LL |     if let Ready(_) = Ready(42) {
 +   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:27:15
++  --> $DIR/redundant_pattern_matching_poll.rs:26:15
 +   |
 +LL |     while let Ready(_) = Ready(42) {}
 +   |     ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:29:15
++  --> $DIR/redundant_pattern_matching_poll.rs:28:15
 +   |
 +LL |     while let Pending = Ready(42) {}
 +   |     ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:35:5
++  --> $DIR/redundant_pattern_matching_poll.rs:30:15
 +   |
 +LL |     while let Pending = Pending::<()> {}
 +   |     ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:40:5
++  --> $DIR/redundant_pattern_matching_poll.rs:36:5
 +   |
 +LL | /     match Ready(42) {
 +LL | |         Ready(_) => true,
 +LL | |         Pending => false,
 +LL | |     };
 +   | |_____^ help: try this: `Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:45:13
++  --> $DIR/redundant_pattern_matching_poll.rs:41:5
 +   |
 +LL | /     match Pending::<()> {
 +LL | |         Ready(_) => false,
 +LL | |         Pending => true,
 +LL | |     };
 +   | |_____^ help: try this: `Pending::<()>.is_pending()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:51:20
++  --> $DIR/redundant_pattern_matching_poll.rs:46:13
 +   |
 +LL |       let _ = match Pending::<()> {
 +   |  _____________^
 +LL | |         Ready(_) => false,
 +LL | |         Pending => true,
 +LL | |     };
 +   | |_____^ help: try this: `Pending::<()>.is_pending()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:55:20
++  --> $DIR/redundant_pattern_matching_poll.rs:52:20
 +   |
 +LL |     let _ = if let Ready(_) = poll { true } else { false };
 +   |             -------^^^^^^^^------- help: try this: `if poll.is_ready()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:57:19
++  --> $DIR/redundant_pattern_matching_poll.rs:56:20
 +   |
 +LL |     let _ = if let Ready(_) = gen_poll() {
 +   |             -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:73:12
++  --> $DIR/redundant_pattern_matching_poll.rs:58:19
 +   |
 +LL |     } else if let Pending = gen_poll() {
 +   |            -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:75:12
++  --> $DIR/redundant_pattern_matching_poll.rs:74:12
 +   |
 +LL |     if let Ready(_) = Ready(42) {}
 +   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:77:15
++  --> $DIR/redundant_pattern_matching_poll.rs:76:12
 +   |
 +LL |     if let Pending = Pending::<()> {}
 +   |     -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:79:15
++  --> $DIR/redundant_pattern_matching_poll.rs:78:15
 +   |
 +LL |     while let Ready(_) = Ready(42) {}
 +   |     ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
-   --> $DIR/redundant_pattern_matching_poll.rs:81:5
++  --> $DIR/redundant_pattern_matching_poll.rs:80:15
 +   |
 +LL |     while let Pending = Pending::<()> {}
 +   |     ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
 +
 +error: redundant pattern matching, consider using `is_ready()`
-   --> $DIR/redundant_pattern_matching_poll.rs:86:5
++  --> $DIR/redundant_pattern_matching_poll.rs:82:5
 +   |
 +LL | /     match Ready(42) {
 +LL | |         Ready(_) => true,
 +LL | |         Pending => false,
 +LL | |     };
 +   | |_____^ help: try this: `Ready(42).is_ready()`
 +
 +error: redundant pattern matching, consider using `is_pending()`
++  --> $DIR/redundant_pattern_matching_poll.rs:87:5
 +   |
 +LL | /     match Pending::<()> {
 +LL | |         Ready(_) => false,
 +LL | |         Pending => true,
 +LL | |     };
 +   | |_____^ help: try this: `Pending::<()>.is_pending()`
 +
 +error: aborting due to 18 previous errors
 +
index e366c75335c20357659021928b32b4e834206997,0000000000000000000000000000000000000000..02e838456d0b574559f34404e79f22ffa158100e
mode 100644,000000..100644
--- /dev/null
@@@ -1,54 -1,0 +1,77 @@@
- #![warn(
-     clippy::all,
-     clippy::pedantic,
-     clippy::shadow_same,
-     clippy::shadow_reuse,
-     clippy::shadow_unrelated
- )]
- #![allow(
-     unused_parens,
-     unused_variables,
-     clippy::manual_unwrap_or,
-     clippy::missing_docs_in_private_items,
-     clippy::single_match
- )]
- fn id<T>(x: T) -> T {
-     x
++#![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
++
++fn shadow_same() {
++    let x = 1;
++    let x = x;
++    let mut x = &x;
++    let x = &mut x;
++    let x = *x;
 +}
 +
- #[must_use]
- fn first(x: (isize, isize)) -> isize {
-     x.0
++fn shadow_reuse() -> Option<()> {
++    let x = ([[0]], ());
++    let x = x.0;
++    let x = x[0];
++    let [x] = x;
++    let x = Some(x);
++    let x = foo(x);
++    let x = || x;
++    let x = Some(1).map(|_| x)?;
++    None
 +}
 +
- fn main() {
-     let mut x = 1;
-     let x = &mut x;
-     let x = { x };
-     let x = (&*x);
-     let x = { *x + 1 };
-     let x = id(x);
-     let x = (1, x);
-     let x = first(x);
-     let y = 1;
-     let x = y;
-     let x;
-     x = 42;
-     let o = Some(1_u8);
-     if let Some(p) = o {
-         assert_eq!(1, p);
++fn shadow_unrelated() {
++    let x = 1;
++    let x = 2;
++}
++
++fn syntax() {
++    fn f(x: u32) {
++        let x = 1;
++    }
++    let x = 1;
++    match Some(1) {
++        Some(1) => {},
++        Some(x) => {
++            let x = 1;
++        },
++        _ => {},
 +    }
-     match o {
-         Some(p) => p, // no error, because the p above is in its own scope
-         None => 0,
++    if let Some(x) = Some(1) {}
++    while let Some(x) = Some(1) {}
++    let _ = |[x]: [u32; 1]| {
++        let x = 1;
 +    };
++}
 +
-     match (x, o) {
-         (1, Some(a)) | (a, Some(1)) => (), // no error though `a` appears twice
-         _ => (),
++fn negative() {
++    match Some(1) {
++        Some(x) if x == 1 => {},
++        Some(x) => {},
++        None => {},
 +    }
++    match [None, Some(1)] {
++        [Some(x), None] | [None, Some(x)] => {},
++        _ => {},
++    }
++    if let Some(x) = Some(1) {
++        let y = 1;
++    } else {
++        let x = 1;
++        let y = 1;
++    }
++    let x = 1;
++    #[allow(clippy::shadow_unrelated)]
++    let x = 1;
++}
++
++fn foo<T>(_: T) {}
++
++fn question_mark() -> Option<()> {
++    let val = 1;
++    // `?` expands with a `val` binding
++    None?;
++    None
 +}
++
++fn main() {}
index 7c1ad2949e91b914cc75034d08034088fd140c99,0000000000000000000000000000000000000000..8b60e072c9342c9c763dc6b8de1740cef3f99dac
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,233 @@@
- error: `x` is shadowed by itself in `&mut x`
-   --> $DIR/shadow.rs:27:5
++error: `x` is shadowed by itself in `x`
++  --> $DIR/shadow.rs:5:9
 +   |
- LL |     let x = &mut x;
-    |     ^^^^^^^^^^^^^^^
++LL |     let x = x;
++   |         ^
 +   |
 +   = note: `-D clippy::shadow-same` implied by `-D warnings`
 +note: previous binding is here
-   --> $DIR/shadow.rs:26:13
++  --> $DIR/shadow.rs:4:9
 +   |
- LL |     let mut x = 1;
-    |             ^
++LL |     let x = 1;
++   |         ^
 +
- error: `x` is shadowed by itself in `{ x }`
-   --> $DIR/shadow.rs:28:5
++error: `mut x` is shadowed by itself in `&x`
++  --> $DIR/shadow.rs:6:13
 +   |
- LL |     let x = { x };
-    |     ^^^^^^^^^^^^^^
++LL |     let mut x = &x;
++   |             ^
 +   |
 +note: previous binding is here
-   --> $DIR/shadow.rs:27:9
++  --> $DIR/shadow.rs:5:9
++   |
++LL |     let x = x;
++   |         ^
++
++error: `x` is shadowed by itself in `&mut x`
++  --> $DIR/shadow.rs:7:9
 +   |
 +LL |     let x = &mut x;
 +   |         ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:6:9
++   |
++LL |     let mut x = &x;
++   |         ^^^^^
 +
- error: `x` is shadowed by itself in `(&*x)`
-   --> $DIR/shadow.rs:29:5
++error: `x` is shadowed by itself in `*x`
++  --> $DIR/shadow.rs:8:9
 +   |
- LL |     let x = (&*x);
-    |     ^^^^^^^^^^^^^^
++LL |     let x = *x;
++   |         ^
 +   |
 +note: previous binding is here
-   --> $DIR/shadow.rs:28:9
++  --> $DIR/shadow.rs:7:9
 +   |
- LL |     let x = { x };
++LL |     let x = &mut x;
 +   |         ^
 +
- error: `x` is shadowed by `{ *x + 1 }` which reuses the original value
-   --> $DIR/shadow.rs:30:9
++error: `x` is shadowed by `x.0` which reuses the original value
++  --> $DIR/shadow.rs:13:9
 +   |
- LL |     let x = { *x + 1 };
++LL |     let x = x.0;
 +   |         ^
 +   |
 +   = note: `-D clippy::shadow-reuse` implied by `-D warnings`
- note: initialization happens here
-   --> $DIR/shadow.rs:30:13
-    |
- LL |     let x = { *x + 1 };
-    |             ^^^^^^^^^^
 +note: previous binding is here
-   --> $DIR/shadow.rs:29:9
++  --> $DIR/shadow.rs:12:9
 +   |
- LL |     let x = (&*x);
++LL |     let x = ([[0]], ());
 +   |         ^
 +
- error: `x` is shadowed by `id(x)` which reuses the original value
-   --> $DIR/shadow.rs:31:9
++error: `x` is shadowed by `x[0]` which reuses the original value
++  --> $DIR/shadow.rs:14:9
 +   |
- LL |     let x = id(x);
++LL |     let x = x[0];
 +   |         ^
 +   |
- note: initialization happens here
-   --> $DIR/shadow.rs:31:13
++note: previous binding is here
++  --> $DIR/shadow.rs:13:9
++   |
++LL |     let x = x.0;
++   |         ^
++
++error: `x` is shadowed by `x` which reuses the original value
++  --> $DIR/shadow.rs:15:10
++   |
++LL |     let [x] = x;
++   |          ^
 +   |
- LL |     let x = id(x);
-    |             ^^^^^
 +note: previous binding is here
-   --> $DIR/shadow.rs:30:9
++  --> $DIR/shadow.rs:14:9
 +   |
- LL |     let x = { *x + 1 };
++LL |     let x = x[0];
 +   |         ^
 +
- error: `x` is shadowed by `(1, x)` which reuses the original value
-   --> $DIR/shadow.rs:32:9
++error: `x` is shadowed by `Some(x)` which reuses the original value
++  --> $DIR/shadow.rs:16:9
 +   |
- LL |     let x = (1, x);
++LL |     let x = Some(x);
 +   |         ^
 +   |
- note: initialization happens here
-   --> $DIR/shadow.rs:32:13
++note: previous binding is here
++  --> $DIR/shadow.rs:15:10
++   |
++LL |     let [x] = x;
++   |          ^
++
++error: `x` is shadowed by `foo(x)` which reuses the original value
++  --> $DIR/shadow.rs:17:9
++   |
++LL |     let x = foo(x);
++   |         ^
 +   |
- LL |     let x = (1, x);
-    |             ^^^^^^
 +note: previous binding is here
-   --> $DIR/shadow.rs:31:9
++  --> $DIR/shadow.rs:16:9
 +   |
- LL |     let x = id(x);
++LL |     let x = Some(x);
 +   |         ^
 +
- error: `x` is shadowed by `first(x)` which reuses the original value
-   --> $DIR/shadow.rs:33:9
++error: `x` is shadowed by `|| x` which reuses the original value
++  --> $DIR/shadow.rs:18:9
 +   |
- LL |     let x = first(x);
++LL |     let x = || x;
 +   |         ^
 +   |
- note: initialization happens here
-   --> $DIR/shadow.rs:33:13
++note: previous binding is here
++  --> $DIR/shadow.rs:17:9
++   |
++LL |     let x = foo(x);
++   |         ^
++
++error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value
++  --> $DIR/shadow.rs:19:9
++   |
++LL |     let x = Some(1).map(|_| x)?;
++   |         ^
 +   |
- LL |     let x = first(x);
-    |             ^^^^^^^^
 +note: previous binding is here
-   --> $DIR/shadow.rs:32:9
++  --> $DIR/shadow.rs:18:9
 +   |
- LL |     let x = (1, x);
++LL |     let x = || x;
 +   |         ^
 +
- error: `x` is being shadowed
-   --> $DIR/shadow.rs:35:9
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:25:9
 +   |
- LL |     let x = y;
++LL |     let x = 2;
 +   |         ^
 +   |
 +   = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
- note: initialization happens here
-   --> $DIR/shadow.rs:35:13
++note: previous binding is here
++  --> $DIR/shadow.rs:24:9
 +   |
- LL |     let x = y;
++LL |     let x = 1;
++   |         ^
++
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:30:13
++   |
++LL |         let x = 1;
 +   |             ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:29:10
++   |
++LL |     fn f(x: u32) {
++   |          ^
++
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:35:14
++   |
++LL |         Some(x) => {
++   |              ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:32:9
++   |
++LL |     let x = 1;
++   |         ^
++
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:36:17
++   |
++LL |             let x = 1;
++   |                 ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:35:14
++   |
++LL |         Some(x) => {
++   |              ^
++
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:40:17
++   |
++LL |     if let Some(x) = Some(1) {}
++   |                 ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:32:9
++   |
++LL |     let x = 1;
++   |         ^
++
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:41:20
++   |
++LL |     while let Some(x) = Some(1) {}
++   |                    ^
++   |
 +note: previous binding is here
-   --> $DIR/shadow.rs:33:9
++  --> $DIR/shadow.rs:32:9
 +   |
- LL |     let x = first(x);
++LL |     let x = 1;
 +   |         ^
 +
- error: `x` shadows a previous declaration
-   --> $DIR/shadow.rs:37:5
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:42:15
 +   |
- LL |     let x;
-    |     ^^^^^^
++LL |     let _ = |[x]: [u32; 1]| {
++   |               ^
 +   |
 +note: previous binding is here
-   --> $DIR/shadow.rs:35:9
++  --> $DIR/shadow.rs:32:9
 +   |
- LL |     let x = y;
++LL |     let x = 1;
 +   |         ^
 +
- error: aborting due to 9 previous errors
++error: `x` shadows a previous, unrelated binding
++  --> $DIR/shadow.rs:43:13
++   |
++LL |         let x = 1;
++   |             ^
++   |
++note: previous binding is here
++  --> $DIR/shadow.rs:42:15
++   |
++LL |     let _ = |[x]: [u32; 1]| {
++   |               ^
++
++error: aborting due to 19 previous errors
 +
index 8c3f36584a5bd1bcee836fdeeef230d59c140d04,0000000000000000000000000000000000000000..3ffcd1a903174d0caee3c1b6c20ea2ec2e6215d0
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
-    = help: make sure you did not confuse `map` with `filter` or `for_each`
 +error: this call to `map()` won't have an effect on the call to `count()`
 +  --> $DIR/suspicious_map.rs:4:13
 +   |
 +LL |     let _ = (0..3).map(|x| x + 2).count();
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::suspicious-map` implied by `-D warnings`
-    = help: make sure you did not confuse `map` with `filter` or `for_each`
++   = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
 +
 +error: this call to `map()` won't have an effect on the call to `count()`
 +  --> $DIR/suspicious_map.rs:7:13
 +   |
 +LL |     let _ = (0..3).map(f).count();
 +   |             ^^^^^^^^^^^^^^^^^^^^^
 +   |
++   = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
 +
 +error: aborting due to 2 previous errors
 +
index f5a341909023ee3429e902862b3344c4e1cdc050,0000000000000000000000000000000000000000..1e74ad2de655aa53c624c6c98bcf1be915f269dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,374 -1,0 +1,380 @@@
- #![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 +// run-rustfix
 +
 +#![warn(clippy::while_let_on_iterator)]
++#![allow(
++    clippy::never_loop,
++    unreachable_code,
++    unused_mut,
++    dead_code,
++    clippy::equatable_if_let
++)]
 +
 +fn base() {
 +    let mut iter = 1..20;
 +    for x in iter {
 +        println!("{}", x);
 +    }
 +
 +    let mut iter = 1..20;
 +    for x in iter {
 +        println!("{}", x);
 +    }
 +
 +    let mut iter = 1..20;
 +    for _ in iter {}
 +
 +    let mut iter = 1..20;
 +    while let None = iter.next() {} // this is fine (if nonsensical)
 +
 +    let mut iter = 1..20;
 +    if let Some(x) = iter.next() {
 +        // also fine
 +        println!("{}", x)
 +    }
 +
 +    // the following shouldn't warn because it can't be written with a for loop
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        println!("next: {:?}", iter.next())
 +    }
 +
 +    // neither can this
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        println!("next: {:?}", iter.next());
 +    }
 +
 +    // or this
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        iter = 1..20;
 +    }
 +}
 +
 +// Issue #1188
 +fn refutable() {
 +    let a = [42, 1337];
 +    let mut b = a.iter();
 +
 +    // consume all the 42s
 +    while let Some(&42) = b.next() {}
 +
 +    let a = [(1, 2, 3)];
 +    let mut b = a.iter();
 +
 +    while let Some(&(1, 2, 3)) = b.next() {}
 +
 +    let a = [Some(42)];
 +    let mut b = a.iter();
 +
 +    while let Some(&None) = b.next() {}
 +
 +    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
 +    for &42 in b {}
 +    for &(1, 2, 3) in b {}
 +    for &Option::None in b.next() {}
 +    // */
 +}
 +
 +fn refutable2() {
 +    // Issue 3780
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.windows(2);
 +        while let Some([x, y]) = it.next() {
 +            println!("x: {}", x);
 +            println!("y: {}", y);
 +        }
 +
 +        let mut it = v.windows(2);
 +        while let Some([x, ..]) = it.next() {
 +            println!("x: {}", x);
 +        }
 +
 +        let mut it = v.windows(2);
 +        while let Some([.., y]) = it.next() {
 +            println!("y: {}", y);
 +        }
 +
 +        let mut it = v.windows(2);
 +        for [..] in it {}
 +
 +        let v = vec![[1], [2], [3]];
 +        let mut it = v.iter();
 +        while let Some([1]) = it.next() {}
 +
 +        let mut it = v.iter();
 +        for [_x] in it {}
 +    }
 +
 +    // binding
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.iter();
 +        while let Some(x @ 1) = it.next() {
 +            println!("{}", x);
 +        }
 +
 +        let v = vec![[1], [2], [3]];
 +        let mut it = v.iter();
 +        for x @ [_] in it {
 +            println!("{:?}", x);
 +        }
 +    }
 +
 +    // false negative
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.iter().map(Some);
 +        while let Some(Some(_) | None) = it.next() {
 +            println!("1");
 +        }
 +    }
 +}
 +
 +fn nested_loops() {
 +    let a = [42, 1337];
 +
 +    loop {
 +        let mut y = a.iter();
 +        for _ in y {
 +            // use a for loop here
 +        }
 +    }
 +}
 +
 +fn issue1121() {
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(&value) = values.iter().next() {
 +        values.remove(&value);
 +    }
 +}
 +
 +fn issue2965() {
 +    // This should not cause an ICE
 +
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(..) = values.iter().next() {}
 +}
 +
 +fn issue3670() {
 +    let array = [Some(0), None, Some(1)];
 +    let mut iter = array.iter();
 +
 +    while let Some(elem) = iter.next() {
 +        let _ = elem.or_else(|| *iter.next()?);
 +    }
 +}
 +
 +fn issue1654() {
 +    // should not lint if the iterator is generated on every iteration
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(..) = values.iter().next() {
 +        values.remove(&1);
 +    }
 +
 +    while let Some(..) = values.iter().map(|x| x + 1).next() {}
 +
 +    let chars = "Hello, World!".char_indices();
 +    while let Some((i, ch)) = chars.clone().next() {
 +        println!("{}: {}", i, ch);
 +    }
 +}
 +
 +fn issue6491() {
 +    // Used in outer loop, needs &mut
 +    let mut it = 1..40;
 +    while let Some(n) = it.next() {
 +        for m in it.by_ref() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("n still is {}", n);
 +    }
 +
 +    // This is fine, inner loop uses a new iterator.
 +    let mut it = 1..40;
 +    for n in it {
 +        let mut it = 1..40;
 +        for m in it {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +
 +        // Weird binding shouldn't change anything.
 +        let (mut it, _) = (1..40, 0);
 +        for m in it {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +
 +        // Used after the loop, needs &mut.
 +        let mut it = 1..40;
 +        for m in it.by_ref() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("next item {}", it.next().unwrap());
 +
 +        println!("n still is {}", n);
 +    }
 +}
 +
 +fn issue6231() {
 +    // Closure in the outer loop, needs &mut
 +    let mut it = 1..40;
 +    let mut opt = Some(0);
 +    while let Some(n) = opt.take().or_else(|| it.next()) {
 +        for m in it.by_ref() {
 +            if n % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("n still is {}", n);
 +    }
 +}
 +
 +fn issue1924() {
 +    struct S<T>(T);
 +    impl<T: Iterator<Item = u32>> S<T> {
 +        fn f(&mut self) -> Option<u32> {
 +            // Used as a field.
 +            for i in self.0.by_ref() {
 +                if !(3..=7).contains(&i) {
 +                    return Some(i);
 +                }
 +            }
 +            None
 +        }
 +
 +        fn f2(&mut self) -> Option<u32> {
 +            // Don't lint, self borrowed inside the loop
 +            while let Some(i) = self.0.next() {
 +                if i == 1 {
 +                    return self.f();
 +                }
 +            }
 +            None
 +        }
 +    }
 +    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
 +        fn f3(&mut self) -> Option<u32> {
 +            // Don't lint, self borrowed inside the loop
 +            while let Some(i) = self.0.0.0.next() {
 +                if i == 1 {
 +                    return self.0.0.f();
 +                }
 +            }
 +            while let Some(i) = self.0.0.0.next() {
 +                if i == 1 {
 +                    return self.f3();
 +                }
 +            }
 +            // This one is fine, a different field is borrowed
 +            for i in self.0.0.0.by_ref() {
 +                if i == 1 {
 +                    return self.0.1.take();
 +                } else {
 +                    self.0.1 = Some(i);
 +                }
 +            }
 +            None
 +        }
 +    }
 +
 +    struct S2<T>(T, u32);
 +    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
 +        type Item = u32;
 +        fn next(&mut self) -> Option<u32> {
 +            self.0.next()
 +        }
 +    }
 +
 +    // Don't lint, field of the iterator is accessed in the loop
 +    let mut it = S2(1..40, 0);
 +    while let Some(n) = it.next() {
 +        if n == it.1 {
 +            break;
 +        }
 +    }
 +
 +    // Needs &mut, field of the iterator is accessed after the loop
 +    let mut it = S2(1..40, 0);
 +    for n in it.by_ref() {
 +        if n == 0 {
 +            break;
 +        }
 +    }
 +    println!("iterator field {}", it.1);
 +}
 +
 +fn issue7249() {
 +    let mut it = 0..10;
 +    let mut x = || {
 +        // Needs &mut, the closure can be called multiple times
 +        for x in it.by_ref() {
 +            if x % 2 == 0 {
 +                break;
 +            }
 +        }
 +    };
 +    x();
 +    x();
 +}
 +
 +fn issue7510() {
 +    let mut it = 0..10;
 +    let it = &mut it;
 +    // Needs to reborrow `it` as the binding isn't mutable
 +    for x in it.by_ref() {
 +        if x % 2 == 0 {
 +            break;
 +        }
 +    }
 +    println!("{}", it.next().unwrap());
 +
 +    struct S<T>(T);
 +    let mut it = 0..10;
 +    let it = S(&mut it);
 +    // Needs to reborrow `it.0` as the binding isn't mutable
 +    for x in it.0.by_ref() {
 +        if x % 2 == 0 {
 +            break;
 +        }
 +    }
 +    println!("{}", it.0.next().unwrap());
 +}
 +
 +fn exact_match_with_single_field() {
 +    struct S<T>(T);
 +    let mut s = S(0..10);
 +    // Don't lint. `s.0` is used inside the loop.
 +    while let Some(_) = s.0.next() {
 +        let _ = &mut s.0;
 +    }
 +}
 +
 +fn main() {
 +    let mut it = 0..20;
 +    for _ in it {
 +        println!("test");
 +    }
 +}
index 72f34257d1f46a631cf7596876dded1da71beedd,0000000000000000000000000000000000000000..69cb636cee8260bb31ce151a97f2ea9a11118955
mode 100644,000000..100644
--- /dev/null
@@@ -1,374 -1,0 +1,380 @@@
- #![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 +// run-rustfix
 +
 +#![warn(clippy::while_let_on_iterator)]
++#![allow(
++    clippy::never_loop,
++    unreachable_code,
++    unused_mut,
++    dead_code,
++    clippy::equatable_if_let
++)]
 +
 +fn base() {
 +    let mut iter = 1..20;
 +    while let Option::Some(x) = iter.next() {
 +        println!("{}", x);
 +    }
 +
 +    let mut iter = 1..20;
 +    while let Some(x) = iter.next() {
 +        println!("{}", x);
 +    }
 +
 +    let mut iter = 1..20;
 +    while let Some(_) = iter.next() {}
 +
 +    let mut iter = 1..20;
 +    while let None = iter.next() {} // this is fine (if nonsensical)
 +
 +    let mut iter = 1..20;
 +    if let Some(x) = iter.next() {
 +        // also fine
 +        println!("{}", x)
 +    }
 +
 +    // the following shouldn't warn because it can't be written with a for loop
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        println!("next: {:?}", iter.next())
 +    }
 +
 +    // neither can this
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        println!("next: {:?}", iter.next());
 +    }
 +
 +    // or this
 +    let mut iter = 1u32..20;
 +    while let Some(_) = iter.next() {
 +        iter = 1..20;
 +    }
 +}
 +
 +// Issue #1188
 +fn refutable() {
 +    let a = [42, 1337];
 +    let mut b = a.iter();
 +
 +    // consume all the 42s
 +    while let Some(&42) = b.next() {}
 +
 +    let a = [(1, 2, 3)];
 +    let mut b = a.iter();
 +
 +    while let Some(&(1, 2, 3)) = b.next() {}
 +
 +    let a = [Some(42)];
 +    let mut b = a.iter();
 +
 +    while let Some(&None) = b.next() {}
 +
 +    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
 +    for &42 in b {}
 +    for &(1, 2, 3) in b {}
 +    for &Option::None in b.next() {}
 +    // */
 +}
 +
 +fn refutable2() {
 +    // Issue 3780
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.windows(2);
 +        while let Some([x, y]) = it.next() {
 +            println!("x: {}", x);
 +            println!("y: {}", y);
 +        }
 +
 +        let mut it = v.windows(2);
 +        while let Some([x, ..]) = it.next() {
 +            println!("x: {}", x);
 +        }
 +
 +        let mut it = v.windows(2);
 +        while let Some([.., y]) = it.next() {
 +            println!("y: {}", y);
 +        }
 +
 +        let mut it = v.windows(2);
 +        while let Some([..]) = it.next() {}
 +
 +        let v = vec![[1], [2], [3]];
 +        let mut it = v.iter();
 +        while let Some([1]) = it.next() {}
 +
 +        let mut it = v.iter();
 +        while let Some([_x]) = it.next() {}
 +    }
 +
 +    // binding
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.iter();
 +        while let Some(x @ 1) = it.next() {
 +            println!("{}", x);
 +        }
 +
 +        let v = vec![[1], [2], [3]];
 +        let mut it = v.iter();
 +        while let Some(x @ [_]) = it.next() {
 +            println!("{:?}", x);
 +        }
 +    }
 +
 +    // false negative
 +    {
 +        let v = vec![1, 2, 3];
 +        let mut it = v.iter().map(Some);
 +        while let Some(Some(_) | None) = it.next() {
 +            println!("1");
 +        }
 +    }
 +}
 +
 +fn nested_loops() {
 +    let a = [42, 1337];
 +
 +    loop {
 +        let mut y = a.iter();
 +        while let Some(_) = y.next() {
 +            // use a for loop here
 +        }
 +    }
 +}
 +
 +fn issue1121() {
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(&value) = values.iter().next() {
 +        values.remove(&value);
 +    }
 +}
 +
 +fn issue2965() {
 +    // This should not cause an ICE
 +
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(..) = values.iter().next() {}
 +}
 +
 +fn issue3670() {
 +    let array = [Some(0), None, Some(1)];
 +    let mut iter = array.iter();
 +
 +    while let Some(elem) = iter.next() {
 +        let _ = elem.or_else(|| *iter.next()?);
 +    }
 +}
 +
 +fn issue1654() {
 +    // should not lint if the iterator is generated on every iteration
 +    use std::collections::HashSet;
 +    let mut values = HashSet::new();
 +    values.insert(1);
 +
 +    while let Some(..) = values.iter().next() {
 +        values.remove(&1);
 +    }
 +
 +    while let Some(..) = values.iter().map(|x| x + 1).next() {}
 +
 +    let chars = "Hello, World!".char_indices();
 +    while let Some((i, ch)) = chars.clone().next() {
 +        println!("{}: {}", i, ch);
 +    }
 +}
 +
 +fn issue6491() {
 +    // Used in outer loop, needs &mut
 +    let mut it = 1..40;
 +    while let Some(n) = it.next() {
 +        while let Some(m) = it.next() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("n still is {}", n);
 +    }
 +
 +    // This is fine, inner loop uses a new iterator.
 +    let mut it = 1..40;
 +    while let Some(n) = it.next() {
 +        let mut it = 1..40;
 +        while let Some(m) = it.next() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +
 +        // Weird binding shouldn't change anything.
 +        let (mut it, _) = (1..40, 0);
 +        while let Some(m) = it.next() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +
 +        // Used after the loop, needs &mut.
 +        let mut it = 1..40;
 +        while let Some(m) = it.next() {
 +            if m % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("next item {}", it.next().unwrap());
 +
 +        println!("n still is {}", n);
 +    }
 +}
 +
 +fn issue6231() {
 +    // Closure in the outer loop, needs &mut
 +    let mut it = 1..40;
 +    let mut opt = Some(0);
 +    while let Some(n) = opt.take().or_else(|| it.next()) {
 +        while let Some(m) = it.next() {
 +            if n % 10 == 0 {
 +                break;
 +            }
 +            println!("doing something with m: {}", m);
 +        }
 +        println!("n still is {}", n);
 +    }
 +}
 +
 +fn issue1924() {
 +    struct S<T>(T);
 +    impl<T: Iterator<Item = u32>> S<T> {
 +        fn f(&mut self) -> Option<u32> {
 +            // Used as a field.
 +            while let Some(i) = self.0.next() {
 +                if i < 3 || i > 7 {
 +                    return Some(i);
 +                }
 +            }
 +            None
 +        }
 +
 +        fn f2(&mut self) -> Option<u32> {
 +            // Don't lint, self borrowed inside the loop
 +            while let Some(i) = self.0.next() {
 +                if i == 1 {
 +                    return self.f();
 +                }
 +            }
 +            None
 +        }
 +    }
 +    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
 +        fn f3(&mut self) -> Option<u32> {
 +            // Don't lint, self borrowed inside the loop
 +            while let Some(i) = self.0.0.0.next() {
 +                if i == 1 {
 +                    return self.0.0.f();
 +                }
 +            }
 +            while let Some(i) = self.0.0.0.next() {
 +                if i == 1 {
 +                    return self.f3();
 +                }
 +            }
 +            // This one is fine, a different field is borrowed
 +            while let Some(i) = self.0.0.0.next() {
 +                if i == 1 {
 +                    return self.0.1.take();
 +                } else {
 +                    self.0.1 = Some(i);
 +                }
 +            }
 +            None
 +        }
 +    }
 +
 +    struct S2<T>(T, u32);
 +    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
 +        type Item = u32;
 +        fn next(&mut self) -> Option<u32> {
 +            self.0.next()
 +        }
 +    }
 +
 +    // Don't lint, field of the iterator is accessed in the loop
 +    let mut it = S2(1..40, 0);
 +    while let Some(n) = it.next() {
 +        if n == it.1 {
 +            break;
 +        }
 +    }
 +
 +    // Needs &mut, field of the iterator is accessed after the loop
 +    let mut it = S2(1..40, 0);
 +    while let Some(n) = it.next() {
 +        if n == 0 {
 +            break;
 +        }
 +    }
 +    println!("iterator field {}", it.1);
 +}
 +
 +fn issue7249() {
 +    let mut it = 0..10;
 +    let mut x = || {
 +        // Needs &mut, the closure can be called multiple times
 +        while let Some(x) = it.next() {
 +            if x % 2 == 0 {
 +                break;
 +            }
 +        }
 +    };
 +    x();
 +    x();
 +}
 +
 +fn issue7510() {
 +    let mut it = 0..10;
 +    let it = &mut it;
 +    // Needs to reborrow `it` as the binding isn't mutable
 +    while let Some(x) = it.next() {
 +        if x % 2 == 0 {
 +            break;
 +        }
 +    }
 +    println!("{}", it.next().unwrap());
 +
 +    struct S<T>(T);
 +    let mut it = 0..10;
 +    let it = S(&mut it);
 +    // Needs to reborrow `it.0` as the binding isn't mutable
 +    while let Some(x) = it.0.next() {
 +        if x % 2 == 0 {
 +            break;
 +        }
 +    }
 +    println!("{}", it.0.next().unwrap());
 +}
 +
 +fn exact_match_with_single_field() {
 +    struct S<T>(T);
 +    let mut s = S(0..10);
 +    // Don't lint. `s.0` is used inside the loop.
 +    while let Some(_) = s.0.next() {
 +        let _ = &mut s.0;
 +    }
 +}
 +
 +fn main() {
 +    let mut it = 0..20;
 +    while let Some(..) = it.next() {
 +        println!("test");
 +    }
 +}
index 5e2fce4491af0956ff4ba97e6b96f9a85c230c35,0000000000000000000000000000000000000000..1a11ba26eef0ffdc7c5c4d9bf75432ca9ad7aff4
mode 100644,000000..100644
--- /dev/null
@@@ -1,132 -1,0 +1,132 @@@
-   --> $DIR/while_let_on_iterator.rs:8:5
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:13:5
++  --> $DIR/while_let_on_iterator.rs:14:5
 +   |
 +LL |     while let Option::Some(x) = iter.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
 +   |
 +   = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:18:5
++  --> $DIR/while_let_on_iterator.rs:19:5
 +   |
 +LL |     while let Some(x) = iter.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:94:9
++  --> $DIR/while_let_on_iterator.rs:24:5
 +   |
 +LL |     while let Some(_) = iter.next() {}
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:101:9
++  --> $DIR/while_let_on_iterator.rs:100:9
 +   |
 +LL |         while let Some([..]) = it.next() {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:114:9
++  --> $DIR/while_let_on_iterator.rs:107:9
 +   |
 +LL |         while let Some([_x]) = it.next() {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:134:9
++  --> $DIR/while_let_on_iterator.rs:120:9
 +   |
 +LL |         while let Some(x @ [_]) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:191:9
++  --> $DIR/while_let_on_iterator.rs:140:9
 +   |
 +LL |         while let Some(_) = y.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:202:5
++  --> $DIR/while_let_on_iterator.rs:197:9
 +   |
 +LL |         while let Some(m) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:204:9
++  --> $DIR/while_let_on_iterator.rs:208:5
 +   |
 +LL |     while let Some(n) = it.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:213:9
++  --> $DIR/while_let_on_iterator.rs:210:9
 +   |
 +LL |         while let Some(m) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:222:9
++  --> $DIR/while_let_on_iterator.rs:219:9
 +   |
 +LL |         while let Some(m) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:239:9
++  --> $DIR/while_let_on_iterator.rs:228:9
 +   |
 +LL |         while let Some(m) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:254:13
++  --> $DIR/while_let_on_iterator.rs:245:9
 +   |
 +LL |         while let Some(m) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:255:20
++  --> $DIR/while_let_on_iterator.rs:260:13
 +   |
 +LL |             while let Some(i) = self.0.next() {
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()`
 +
 +error: manual `!RangeInclusive::contains` implementation
-   --> $DIR/while_let_on_iterator.rs:286:13
++  --> $DIR/while_let_on_iterator.rs:261:20
 +   |
 +LL |                 if i < 3 || i > 7 {
 +   |                    ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)`
 +   |
 +   = note: `-D clippy::manual-range-contains` implied by `-D warnings`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:315:5
++  --> $DIR/while_let_on_iterator.rs:292:13
 +   |
 +LL |             while let Some(i) = self.0.0.0.next() {
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:327:9
++  --> $DIR/while_let_on_iterator.rs:321:5
 +   |
 +LL |     while let Some(n) = it.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:341:5
++  --> $DIR/while_let_on_iterator.rs:333:9
 +   |
 +LL |         while let Some(x) = it.next() {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:352:5
++  --> $DIR/while_let_on_iterator.rs:347:5
 +   |
 +LL |     while let Some(x) = it.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
 +
 +error: this loop could be written as a `for` loop
-   --> $DIR/while_let_on_iterator.rs:371:5
++  --> $DIR/while_let_on_iterator.rs:358:5
 +   |
 +LL |     while let Some(x) = it.0.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()`
 +
 +error: this loop could be written as a `for` loop
++  --> $DIR/while_let_on_iterator.rs:377:5
 +   |
 +LL |     while let Some(..) = it.next() {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 +
 +error: aborting due to 21 previous errors
 +
index 528f8953b25d8b81b40633a399def3fd9762726e,0000000000000000000000000000000000000000..5dd2ba3d5f53b92cdcbd2a967d264e64a5428fa0
mode 100755,000000..100755
--- /dev/null
@@@ -1,21 -1,0 +1,22 @@@
 +#!/bin/sh
 +
 +# hide output
 +set -e
 +
 +# Update lints
 +cargo dev update_lints
 +git add clippy_lints/src/lib.rs
++git add clippy_lints/src/lib.*.rs
 +
 +# Formatting:
 +#     Git will not automatically add the formatted code to the staged changes once
 +#     fmt was executed. This collects all staged files rs files that are currently staged.
 +#     They will later be added back.
 +#
 +#     This was proudly stolen and adjusted from here:
 +#     https://medium.com/@harshitbangar/automatic-code-formatting-with-git-66c3c5c26798
 +files=$( (git diff --cached --name-only --diff-filter=ACMR | grep -Ei "\.rs$") || true)
 +if [ ! -z "${files}" ]; then
 +    cargo dev fmt
 +    git add $(echo "$files" | paste -s -d " " -)
 +fi