]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '984330a6ee3c4d15626685d6dc8b7b759ff630bd' into clippyup
authorflip1995 <philipp.krones@embecosm.com>
Thu, 7 Apr 2022 17:39:59 +0000 (18:39 +0100)
committerflip1995 <philipp.krones@embecosm.com>
Fri, 8 Apr 2022 09:06:10 +0000 (10:06 +0100)
175 files changed:
1  2 
src/tools/clippy/CHANGELOG.md
src/tools/clippy/Cargo.toml
src/tools/clippy/clippy_dev/Cargo.toml
src/tools/clippy/clippy_dev/src/bless.rs
src/tools/clippy/clippy_dev/src/lib.rs
src/tools/clippy/clippy_dev/src/lint.rs
src/tools/clippy/clippy_dev/src/main.rs
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/lib.register_all.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_lints.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/single_element_loop.rs
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/matches/mod.rs
src/tools/clippy/clippy_lints/src/matches/needless_match.rs
src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
src/tools/clippy/clippy_lints/src/methods/err_expect.rs
src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
src/tools/clippy/clippy_lints/src/methods/map_identity.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
src/tools/clippy/clippy_lints/src/module_style.rs
src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/use_self.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/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/doc/release.md
src/tools/clippy/rust-toolchain
src/tools/clippy/src/driver.rs
src/tools/clippy/tests/check-fmt.rs
src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr
src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr
src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.rs
src/tools/clippy/tests/ui/auxiliary/proc_macro_unsafe.rs
src/tools/clippy/tests/ui/bytes_nth.stderr
src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
src/tools/clippy/tests/ui/cast.rs
src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
src/tools/clippy/tests/ui/cast_alignment.rs
src/tools/clippy/tests/ui/cast_alignment.stderr
src/tools/clippy/tests/ui/crashes/ice-2774.rs
src/tools/clippy/tests/ui/crashes/ice-6179.rs
src/tools/clippy/tests/ui/crashes/ice-6792.rs
src/tools/clippy/tests/ui/crashes/ice-7868.stderr
src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
src/tools/clippy/tests/ui/crashes/regressions.rs
src/tools/clippy/tests/ui/crate_in_macro_def.fixed
src/tools/clippy/tests/ui/crate_in_macro_def.rs
src/tools/clippy/tests/ui/crate_in_macro_def.stderr
src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
src/tools/clippy/tests/ui/drop_forget_copy.rs
src/tools/clippy/tests/ui/drop_forget_copy.stderr
src/tools/clippy/tests/ui/drop_non_drop.rs
src/tools/clippy/tests/ui/drop_non_drop.stderr
src/tools/clippy/tests/ui/drop_ref.rs
src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr
src/tools/clippy/tests/ui/err_expect.fixed
src/tools/clippy/tests/ui/err_expect.rs
src/tools/clippy/tests/ui/err_expect.stderr
src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
src/tools/clippy/tests/ui/forget_non_drop.rs
src/tools/clippy/tests/ui/forget_non_drop.stderr
src/tools/clippy/tests/ui/forget_ref.rs
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/implicit_clone.rs
src/tools/clippy/tests/ui/indexing_slicing_index.rs
src/tools/clippy/tests/ui/indexing_slicing_index.stderr
src/tools/clippy/tests/ui/iter_nth_zero.fixed
src/tools/clippy/tests/ui/iter_nth_zero.rs
src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
src/tools/clippy/tests/ui/iter_overeager_cloned.rs
src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
src/tools/clippy/tests/ui/large_types_passed_by_value.rs
src/tools/clippy/tests/ui/let_and_return.rs
src/tools/clippy/tests/ui/let_underscore_must_use.rs
src/tools/clippy/tests/ui/manual_async_fn.fixed
src/tools/clippy/tests/ui/manual_async_fn.rs
src/tools/clippy/tests/ui/manual_unwrap_or.fixed
src/tools/clippy/tests/ui/manual_unwrap_or.rs
src/tools/clippy/tests/ui/map_identity.fixed
src/tools/clippy/tests/ui/map_identity.rs
src/tools/clippy/tests/ui/map_identity.stderr
src/tools/clippy/tests/ui/map_unit_fn.rs
src/tools/clippy/tests/ui/min_rust_version_attr.rs
src/tools/clippy/tests/ui/min_rust_version_attr.stderr
src/tools/clippy/tests/ui/missing_inline.rs
src/tools/clippy/tests/ui/module_name_repetitions.rs
src/tools/clippy/tests/ui/module_name_repetitions.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_arbitrary_self_type_unfixable.rs
src/tools/clippy/tests/ui/needless_lifetimes.rs
src/tools/clippy/tests/ui/needless_match.fixed
src/tools/clippy/tests/ui/needless_match.rs
src/tools/clippy/tests/ui/needless_match.stderr
src/tools/clippy/tests/ui/needless_option_as_deref.fixed
src/tools/clippy/tests/ui/needless_option_as_deref.rs
src/tools/clippy/tests/ui/needless_option_as_deref.stderr
src/tools/clippy/tests/ui/no_effect.rs
src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
src/tools/clippy/tests/ui/or_then_unwrap.fixed
src/tools/clippy/tests/ui/or_then_unwrap.rs
src/tools/clippy/tests/ui/panicking_macros.rs
src/tools/clippy/tests/ui/panicking_macros.stderr
src/tools/clippy/tests/ui/ptr_arg.rs
src/tools/clippy/tests/ui/recursive_format_impl.rs
src/tools/clippy/tests/ui/redundant_allocation.rs
src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
src/tools/clippy/tests/ui/redundant_clone.fixed
src/tools/clippy/tests/ui/redundant_clone.rs
src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
src/tools/clippy/tests/ui/same_item_push.rs
src/tools/clippy/tests/ui/single_element_loop.fixed
src/tools/clippy/tests/ui/single_element_loop.rs
src/tools/clippy/tests/ui/single_element_loop.stderr
src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
src/tools/clippy/tests/ui/transmute.rs
src/tools/clippy/tests/ui/transmute.stderr
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
src/tools/clippy/tests/ui/unnecessary_cast.rs
src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed
src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs
src/tools/clippy/tests/ui/unsafe_derive_deserialize.rs
src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
src/tools/clippy/tests/ui/unused_self.rs
src/tools/clippy/tests/ui/use_self.fixed
src/tools/clippy/tests/ui/use_self.rs
src/tools/clippy/tests/ui/useless_attribute.fixed
src/tools/clippy/tests/ui/useless_attribute.rs
src/tools/clippy/tests/versioncheck.rs

index 88f71931d92b58432cfaa4e003422562bf9de0c0,0000000000000000000000000000000000000000..b4097ea86a5185ce492067bad0ffb086733ad4c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,3576 -1,0 +1,3714 @@@
- [0eff589...master](https://github.com/rust-lang/rust-clippy/compare/0eff589...master)
 +# Changelog
 +
 +All notable changes to this project will be documented in this file.
 +See [Changelog Update](doc/changelog_update.md) if you want to update this
 +document.
 +
 +## Unreleased / In Rust Nightly
 +
- ## Rust 1.59 (beta)
++[57b3c4b...master](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...master)
 +
- Current beta, release 2022-02-24
++## Rust 1.60
 +
- Current stable, released 2022-01-13
++Current stable, released 2022-04-07
++
++[0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b)
++
++### New Lints
++
++* [`single_char_lifetime_names`]
++  [#8236](https://github.com/rust-lang/rust-clippy/pull/8236)
++* [`iter_overeager_cloned`]
++  [#8203](https://github.com/rust-lang/rust-clippy/pull/8203)
++* [`transmute_undefined_repr`]
++  [#8398](https://github.com/rust-lang/rust-clippy/pull/8398)
++* [`default_union_representation`]
++  [#8289](https://github.com/rust-lang/rust-clippy/pull/8289)
++* [`manual_bits`]
++  [#8213](https://github.com/rust-lang/rust-clippy/pull/8213)
++* [`borrow_as_ptr`]
++  [#8210](https://github.com/rust-lang/rust-clippy/pull/8210)
++
++### Moves and Deprecations
++
++* Moved [`disallowed_methods`] and [`disallowed_types`] to `style` (now warn-by-default)
++  [#8261](https://github.com/rust-lang/rust-clippy/pull/8261)
++* Rename `ref_in_deref` to [`needless_borrow`]
++  [#8217](https://github.com/rust-lang/rust-clippy/pull/8217)
++* Moved [`mutex_atomic`] to `nursery` (now allow-by-default)
++  [#8260](https://github.com/rust-lang/rust-clippy/pull/8260)
++
++### Enhancements
++
++* [`ptr_arg`]: Now takes the argument usage into account and lints for mutable references
++  [#8271](https://github.com/rust-lang/rust-clippy/pull/8271)
++* [`unused_io_amount`]: Now supports async read and write traits
++  [#8179](https://github.com/rust-lang/rust-clippy/pull/8179)
++* [`while_let_on_iterator`]: Improved detection to catch more cases
++  [#8221](https://github.com/rust-lang/rust-clippy/pull/8221)
++* [`trait_duplication_in_bounds`]: Now covers trait functions with `Self` bounds
++  [#8252](https://github.com/rust-lang/rust-clippy/pull/8252)
++* [`unwrap_used`]: Now works for `.get(i).unwrap()` and `.get_mut(i).unwrap()`
++  [#8372](https://github.com/rust-lang/rust-clippy/pull/8372)
++* [`map_clone`]: The suggestion takes `msrv` into account
++  [#8280](https://github.com/rust-lang/rust-clippy/pull/8280)
++* [`manual_bits`] and [`borrow_as_ptr`]: Now track the `clippy::msrv` attribute
++  [#8280](https://github.com/rust-lang/rust-clippy/pull/8280)
++* [`disallowed_methods`]: Now works for methods on primitive types
++  [#8112](https://github.com/rust-lang/rust-clippy/pull/8112)
++* [`not_unsafe_ptr_arg_deref`]: Now works for type aliases
++  [#8273](https://github.com/rust-lang/rust-clippy/pull/8273)
++* [`needless_question_mark`]: Now works for async functions
++  [#8311](https://github.com/rust-lang/rust-clippy/pull/8311)
++* [`iter_not_returning_iterator`]: Now handles type projections
++  [#8228](https://github.com/rust-lang/rust-clippy/pull/8228)
++* [`wrong_self_convention`]: Now detects wrong `self` references in more cases
++  [#8208](https://github.com/rust-lang/rust-clippy/pull/8208)
++* [`single_match`]: Now works for `match` statements with tuples
++  [#8322](https://github.com/rust-lang/rust-clippy/pull/8322)
++
++### False Positive Fixes
++
++* [`erasing_op`]: No longer triggers if the output type changes
++  [#8204](https://github.com/rust-lang/rust-clippy/pull/8204)
++* [`if_same_then_else`]: No longer triggers for `if let` statements
++  [#8297](https://github.com/rust-lang/rust-clippy/pull/8297)
++* [`manual_memcpy`]: No longer lints on `VecDeque`
++  [#8226](https://github.com/rust-lang/rust-clippy/pull/8226)
++* [`trait_duplication_in_bounds`]: Now takes path segments into account
++  [#8315](https://github.com/rust-lang/rust-clippy/pull/8315)
++* [`deref_addrof`]: No longer lints when the dereference or borrow occurs in different a context
++  [#8268](https://github.com/rust-lang/rust-clippy/pull/8268)
++* [`type_repetition_in_bounds`]: Now checks for full equality to prevent false positives
++  [#8224](https://github.com/rust-lang/rust-clippy/pull/8224)
++* [`ptr_arg`]: No longer lint for mutable references in traits
++  [#8369](https://github.com/rust-lang/rust-clippy/pull/8369)
++* [`implicit_clone`]: No longer lints for double references
++  [#8231](https://github.com/rust-lang/rust-clippy/pull/8231)
++* [`needless_lifetimes`]: No longer lints lifetimes for explicit `self` types
++  [#8278](https://github.com/rust-lang/rust-clippy/pull/8278)
++* [`op_ref`]: No longer lints in `BinOp` impl if that can cause recursion
++  [#8298](https://github.com/rust-lang/rust-clippy/pull/8298)
++* [`enum_variant_names`]: No longer triggers for empty variant names
++  [#8329](https://github.com/rust-lang/rust-clippy/pull/8329)
++* [`redundant_closure`]: No longer lints for `Arc<T>` or `Rc<T>`
++  [#8193](https://github.com/rust-lang/rust-clippy/pull/8193)
++* [`iter_not_returning_iterator`]: No longer lints on trait implementations but therefore on trait definitions
++  [#8228](https://github.com/rust-lang/rust-clippy/pull/8228)
++* [`single_match`]: No longer lints on exhaustive enum patterns without a wildcard
++  [#8322](https://github.com/rust-lang/rust-clippy/pull/8322)
++* [`manual_swap`]: No longer lints on cases that involve automatic dereferences
++  [#8220](https://github.com/rust-lang/rust-clippy/pull/8220)
++* [`useless_format`]: Now works for implicit named arguments
++  [#8295](https://github.com/rust-lang/rust-clippy/pull/8295)
++
++### Suggestion Fixes/Improvements
++
++* [`needless_borrow`]: Prevent mutable borrows being moved and suggest removing the borrow on method calls
++  [#8217](https://github.com/rust-lang/rust-clippy/pull/8217)
++* [`chars_next_cmp`]: Correctly excapes the suggestion
++  [#8376](https://github.com/rust-lang/rust-clippy/pull/8376)
++* [`explicit_write`]: Add suggestions for `write!`s with format arguments
++  [#8365](https://github.com/rust-lang/rust-clippy/pull/8365)
++* [`manual_memcpy`]: Suggests `copy_from_slice` when applicable
++  [#8226](https://github.com/rust-lang/rust-clippy/pull/8226)
++* [`or_fun_call`]: Improved suggestion display for long arguments
++  [#8292](https://github.com/rust-lang/rust-clippy/pull/8292)
++* [`unnecessary_cast`]: Now correctly includes the sign
++  [#8350](https://github.com/rust-lang/rust-clippy/pull/8350)
++* [`cmp_owned`]: No longer flips the comparison order
++  [#8299](https://github.com/rust-lang/rust-clippy/pull/8299)
++* [`explicit_counter_loop`]: Now correctly suggests `iter()` on references
++  [#8382](https://github.com/rust-lang/rust-clippy/pull/8382)
++
++### ICE Fixes
++
++* [`manual_split_once`]
++  [#8250](https://github.com/rust-lang/rust-clippy/pull/8250)
++
++### Documentation Improvements
++
++* [`map_flatten`]: Add documentation for the `Option` type
++  [#8354](https://github.com/rust-lang/rust-clippy/pull/8354)
++* Document that Clippy's driver might use a different code generation than rustc
++  [#8037](https://github.com/rust-lang/rust-clippy/pull/8037)
++* Clippy's lint list will now automatically focus the search box
++  [#8343](https://github.com/rust-lang/rust-clippy/pull/8343)
++
++### Others
++
++* Clippy now warns if we find multiple Clippy config files exist
++  [#8326](https://github.com/rust-lang/rust-clippy/pull/8326)
++
++## Rust 1.59
++
++Released 2022-02-24
 +
 +[e181011...0eff589](https://github.com/rust-lang/rust-clippy/compare/e181011...0eff589)
 +
 +### New Lints
 +
 +* [`index_refutable_slice`]
 +  [#7643](https://github.com/rust-lang/rust-clippy/pull/7643)
 +* [`needless_splitn`]
 +  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
 +* [`unnecessary_to_owned`]
 +  [#7978](https://github.com/rust-lang/rust-clippy/pull/7978)
 +* [`needless_late_init`]
 +  [#7995](https://github.com/rust-lang/rust-clippy/pull/7995)
 +* [`octal_escapes`] [#8007](https://github.com/rust-lang/rust-clippy/pull/8007)
 +* [`return_self_not_must_use`]
 +  [#8071](https://github.com/rust-lang/rust-clippy/pull/8071)
 +* [`init_numbered_fields`]
 +  [#8170](https://github.com/rust-lang/rust-clippy/pull/8170)
 +
 +### Moves and Deprecations
 +
 +* Move `if_then_panic` to `pedantic` and rename to [`manual_assert`] (now
 +  allow-by-default) [#7810](https://github.com/rust-lang/rust-clippy/pull/7810)
 +* Rename `disallow_type` to [`disallowed_types`] and `disallowed_method` to
 +  [`disallowed_methods`]
 +  [#7984](https://github.com/rust-lang/rust-clippy/pull/7984)
 +* Move [`map_flatten`] to `complexity` (now warn-by-default)
 +  [#8054](https://github.com/rust-lang/rust-clippy/pull/8054)
 +
 +### Enhancements
 +
 +* [`match_overlapping_arm`]: Fix false negative where after included ranges,
 +  overlapping ranges weren't linted anymore
 +  [#7909](https://github.com/rust-lang/rust-clippy/pull/7909)
 +* [`deprecated_cfg_attr`]: Now takes the specified MSRV into account
 +  [#7944](https://github.com/rust-lang/rust-clippy/pull/7944)
 +* [`cast_lossless`]: Now also lints for `bool` to integer casts
 +  [#7948](https://github.com/rust-lang/rust-clippy/pull/7948)
 +* [`let_underscore_lock`]: Also emit lints for the `parking_lot` crate
 +  [#7957](https://github.com/rust-lang/rust-clippy/pull/7957)
 +* [`needless_borrow`]
 +  [#7977](https://github.com/rust-lang/rust-clippy/pull/7977)
 +    * Lint when a borrow is auto-dereffed more than once
 +    * Lint in the trailing expression of a block for a match arm
 +* [`strlen_on_c_strings`]
 +  [8001](https://github.com/rust-lang/rust-clippy/pull/8001)
 +    * Lint when used without a fully-qualified path
 +    * Suggest removing the surrounding unsafe block when possible
 +* [`non_ascii_literal`]: Now also lints on `char`s, not just `string`s
 +  [#8034](https://github.com/rust-lang/rust-clippy/pull/8034)
 +* [`single_char_pattern`]: Now also lints on `split_inclusive`, `split_once`,
 +  `rsplit_once`, `replace`, and `replacen`
 +  [#8077](https://github.com/rust-lang/rust-clippy/pull/8077)
 +* [`unwrap_or_else_default`]: Now also lints on `std` constructors like
 +  `Vec::new`, `HashSet::new`, and `HashMap::new`
 +  [#8163](https://github.com/rust-lang/rust-clippy/pull/8163)
 +* [`shadow_reuse`]: Now also lints on shadowed `if let` bindings, instead of
 +  [`shadow_unrelated`]
 +  [#8165](https://github.com/rust-lang/rust-clippy/pull/8165)
 +
 +### False Positive Fixes
 +
 +* [`or_fun_call`], [`unnecessary_lazy_evaluations`]: Improve heuristics, so that
 +  cheap functions (e.g. calling `.len()` on a `Vec`) won't get linted anymore
 +  [#7639](https://github.com/rust-lang/rust-clippy/pull/7639)
 +* [`manual_split_once`]: No longer suggests code changing the original behavior
 +  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
 +* Don't show [`no_effect`] or [`unnecessary_operation`] warning for unit struct
 +  implementing `FnOnce`
 +  [#7898](https://github.com/rust-lang/rust-clippy/pull/7898)
 +* [`semicolon_if_nothing_returned`]: Fixed a bug, where the lint wrongly
 +  triggered on `let-else` statements
 +  [#7955](https://github.com/rust-lang/rust-clippy/pull/7955)
 +* [`if_then_some_else_none`]: No longer lints if there is an early return
 +  [#7980](https://github.com/rust-lang/rust-clippy/pull/7980)
 +* [`needless_collect`]: No longer suggests removal of `collect` when removal
 +  would create code requiring mutably borrowing a value multiple times
 +  [#7982](https://github.com/rust-lang/rust-clippy/pull/7982)
 +* [`shadow_same`]: Fix false positive for `async` function's params
 +  [#7997](https://github.com/rust-lang/rust-clippy/pull/7997)
 +* [`suboptimal_flops`]: No longer triggers in constant functions
 +  [#8009](https://github.com/rust-lang/rust-clippy/pull/8009)
 +* [`type_complexity`]: No longer lints on associated types in traits
 +  [#8030](https://github.com/rust-lang/rust-clippy/pull/8030)
 +* [`question_mark`]: No longer lints if returned object is not local
 +  [#8080](https://github.com/rust-lang/rust-clippy/pull/8080)
 +* [`option_if_let_else`]: No longer lint on complex sub-patterns
 +  [#8086](https://github.com/rust-lang/rust-clippy/pull/8086)
 +* [`blocks_in_if_conditions`]: No longer lints on empty closures
 +  [#8100](https://github.com/rust-lang/rust-clippy/pull/8100)
 +* [`enum_variant_names`]: No longer lint when first prefix is only a substring
 +  of a camel-case word
 +  [#8127](https://github.com/rust-lang/rust-clippy/pull/8127)
 +* [`identity_op`]: Only lint on integral operands
 +  [#8183](https://github.com/rust-lang/rust-clippy/pull/8183)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`search_is_some`]: Fix suggestion for `any()` not taking item by reference
 +  [#7463](https://github.com/rust-lang/rust-clippy/pull/7463)
 +* [`almost_swapped`]: Now detects if there is a `no_std` or `no_core` attribute
 +  and adapts the suggestion accordingly
 +  [#7877](https://github.com/rust-lang/rust-clippy/pull/7877)
 +* [`redundant_pattern_matching`]: Fix suggestion for deref expressions
 +  [#7949](https://github.com/rust-lang/rust-clippy/pull/7949)
 +* [`explicit_counter_loop`]: Now also produces a suggestion for non-`usize`
 +  types [#7950](https://github.com/rust-lang/rust-clippy/pull/7950)
 +* [`manual_map`]: Fix suggestion when used with unsafe functions and blocks
 +  [#7968](https://github.com/rust-lang/rust-clippy/pull/7968)
 +* [`option_map_or_none`]: Suggest `map` over `and_then` when possible
 +  [#7971](https://github.com/rust-lang/rust-clippy/pull/7971)
 +* [`option_if_let_else`]: No longer expands macros in the suggestion
 +  [#7974](https://github.com/rust-lang/rust-clippy/pull/7974)
 +* [`iter_cloned_collect`]: Suggest `copied` over `cloned` when possible
 +  [#8006](https://github.com/rust-lang/rust-clippy/pull/8006)
 +* [`doc_markdown`]: No longer uses inline hints to improve readability of
 +  suggestion [#8011](https://github.com/rust-lang/rust-clippy/pull/8011)
 +* [`needless_question_mark`]: Now better explains the suggestion
 +  [#8028](https://github.com/rust-lang/rust-clippy/pull/8028)
 +* [`single_char_pattern`]: Escape backslash `\` in suggestion
 +  [#8067](https://github.com/rust-lang/rust-clippy/pull/8067)
 +* [`needless_bool`]: Suggest `a != b` over `!(a == b)`
 +  [#8117](https://github.com/rust-lang/rust-clippy/pull/8117)
 +* [`iter_skip_next`]: Suggest to add a `mut` if it is necessary in order to
 +  apply this lints suggestion
 +  [#8133](https://github.com/rust-lang/rust-clippy/pull/8133)
 +* [`neg_multiply`]: Now produces a suggestion
 +  [#8144](https://github.com/rust-lang/rust-clippy/pull/8144)
 +* [`needless_return`]: Now suggests the unit type `()` over an empty block `{}`
 +  in match arms [#8185](https://github.com/rust-lang/rust-clippy/pull/8185)
 +* [`suboptimal_flops`]: Now gives a syntactically correct suggestion for
 +  `to_radians` and `to_degrees`
 +  [#8187](https://github.com/rust-lang/rust-clippy/pull/8187)
 +
 +### ICE Fixes
 +
 +* [`undocumented_unsafe_blocks`]
 +  [#7945](https://github.com/rust-lang/rust-clippy/pull/7945)
 +  [#7988](https://github.com/rust-lang/rust-clippy/pull/7988)
 +* [`unnecessary_cast`]
 +  [#8167](https://github.com/rust-lang/rust-clippy/pull/8167)
 +
 +### Documentation Improvements
 +
 +* [`print_stdout`], [`print_stderr`], [`dbg_macro`]: Document how the lint level
 +  can be changed crate-wide
 +  [#8040](https://github.com/rust-lang/rust-clippy/pull/8040)
 +* Added a note to the `README` that config changes don't apply to already
 +  compiled code [#8175](https://github.com/rust-lang/rust-clippy/pull/8175)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now displays
 +  the version a lint was added. :tada:
 +  [#7813](https://github.com/rust-lang/rust-clippy/pull/7813)
 +* New and improved issue templates
 +  [#8032](https://github.com/rust-lang/rust-clippy/pull/8032)
 +* _Dev:_ Add `cargo dev lint` command, to run your modified Clippy version on a
 +  file [#7917](https://github.com/rust-lang/rust-clippy/pull/7917)
 +
 +## Rust 1.58
 +
++Released 2022-01-13
 +
 +[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011)
 +
 +### Rust 1.58.1
 +
 +* Move [`non_send_fields_in_send_ty`] to `nursery` (now allow-by-default)
 +  [#8075](https://github.com/rust-lang/rust-clippy/pull/8075)
 +* [`useless_format`]: Handle implicit named arguments
 +  [#8295](https://github.com/rust-lang/rust-clippy/pull/8295)
 +
 +### New lints
 +
 +* [`transmute_num_to_bytes`]
 +  [#7805](https://github.com/rust-lang/rust-clippy/pull/7805)
 +* [`match_str_case_mismatch`]
 +  [#7806](https://github.com/rust-lang/rust-clippy/pull/7806)
 +* [`format_in_format_args`], [`to_string_in_format_args`]
 +  [#7743](https://github.com/rust-lang/rust-clippy/pull/7743)
 +* [`uninit_vec`]
 +  [#7682](https://github.com/rust-lang/rust-clippy/pull/7682)
 +* [`fn_to_numeric_cast_any`]
 +  [#7705](https://github.com/rust-lang/rust-clippy/pull/7705)
 +* [`undocumented_unsafe_blocks`]
 +  [#7748](https://github.com/rust-lang/rust-clippy/pull/7748)
 +* [`trailing_empty_array`]
 +  [#7838](https://github.com/rust-lang/rust-clippy/pull/7838)
 +* [`string_slice`]
 +  [#7878](https://github.com/rust-lang/rust-clippy/pull/7878)
 +
 +### Moves or deprecations of lints
 +
 +* Move [`non_send_fields_in_send_ty`] to `suspicious`
 +  [#7874](https://github.com/rust-lang/rust-clippy/pull/7874)
 +* Move [`non_ascii_literal`] to `restriction`
 +  [#7907](https://github.com/rust-lang/rust-clippy/pull/7907)
 +
 +### Changes that expand what code existing lints cover
 +
 +* [`question_mark`] now covers `Result`
 +  [#7840](https://github.com/rust-lang/rust-clippy/pull/7840)
 +* Make [`useless_format`] recognize bare `format!("")`
 +  [#7801](https://github.com/rust-lang/rust-clippy/pull/7801)
 +* Lint on underscored variables with no side effects in [`no_effect`]
 +  [#7775](https://github.com/rust-lang/rust-clippy/pull/7775)
 +* Expand [`match_ref_pats`] to check for multiple reference patterns
 +  [#7800](https://github.com/rust-lang/rust-clippy/pull/7800)
 +
 +### False positive fixes
 +
 +* Fix false positive of [`implicit_saturating_sub`] with `else` clause
 +  [#7832](https://github.com/rust-lang/rust-clippy/pull/7832)
 +* Fix [`question_mark`] when there is call in conditional predicate
 +  [#7860](https://github.com/rust-lang/rust-clippy/pull/7860)
 +* [`mut_mut`] no longer lints when type is defined in external macros
 +  [#7795](https://github.com/rust-lang/rust-clippy/pull/7795)
 +* Avoid [`eq_op`] in test functions
 +  [#7811](https://github.com/rust-lang/rust-clippy/pull/7811)
 +* [`cast_possible_truncation`] no longer lints when cast is coming from `signum`
 +  method call [#7850](https://github.com/rust-lang/rust-clippy/pull/7850)
 +* [`match_str_case_mismatch`] no longer lints on uncased characters
 +  [#7865](https://github.com/rust-lang/rust-clippy/pull/7865)
 +* [`ptr_arg`] no longer lints references to type aliases
 +  [#7890](https://github.com/rust-lang/rust-clippy/pull/7890)
 +* [`missing_safety_doc`] now also accepts "implementation safety" headers
 +  [#7856](https://github.com/rust-lang/rust-clippy/pull/7856)
 +* [`missing_safety_doc`] no longer lints if any parent has `#[doc(hidden)]`
 +  attribute [#7849](https://github.com/rust-lang/rust-clippy/pull/7849)
 +* [`if_not_else`] now ignores else-if statements
 +  [#7895](https://github.com/rust-lang/rust-clippy/pull/7895)
 +* Avoid linting [`cast_possible_truncation`] on bit-reducing operations
 +  [#7819](https://github.com/rust-lang/rust-clippy/pull/7819)
 +* Avoid linting [`field_reassign_with_default`] when `Drop` and `Copy` are
 +  involved [#7794](https://github.com/rust-lang/rust-clippy/pull/7794)
 +* [`unnecessary_sort_by`] now checks if argument implements `Ord` trait
 +  [#7824](https://github.com/rust-lang/rust-clippy/pull/7824)
 +* Fix false positive in [`match_overlapping_arm`]
 +  [#7847](https://github.com/rust-lang/rust-clippy/pull/7847)
 +* Prevent [`needless_lifetimes`] false positive in `async` function definition
 +  [#7901](https://github.com/rust-lang/rust-clippy/pull/7901)
 +
 +### Suggestion fixes/improvements
 +
 +* Keep an initial `::` when [`doc_markdown`] suggests to use ticks
 +  [#7916](https://github.com/rust-lang/rust-clippy/pull/7916)
 +* Add a machine applicable suggestion for the [`doc_markdown`] missing backticks
 +  lint [#7904](https://github.com/rust-lang/rust-clippy/pull/7904)
 +* [`equatable_if_let`] no longer expands macros in the suggestion
 +  [#7788](https://github.com/rust-lang/rust-clippy/pull/7788)
 +* Make [`shadow_reuse`] suggestion less verbose
 +  [#7782](https://github.com/rust-lang/rust-clippy/pull/7782)
 +
 +### ICE fixes
 +
 +* Fix ICE in [`enum_variant_names`]
 +  [#7873](https://github.com/rust-lang/rust-clippy/pull/7873)
 +* Fix ICE in [`undocumented_unsafe_blocks`]
 +  [#7891](https://github.com/rust-lang/rust-clippy/pull/7891)
 +
 +### Documentation improvements
 +
 +* Fixed naive doc formatting for `#[must_use]` lints ([`must_use_unit`],
 +  [`double_must_use`], [`must_use_candidate`], [`let_underscore_must_use`])
 +  [#7827](https://github.com/rust-lang/rust-clippy/pull/7827)
 +* Fix typo in example for [`match_result_ok`]
 +  [#7815](https://github.com/rust-lang/rust-clippy/pull/7815)
 +
 +### Others
 +
 +* Allow giving reasons for [`disallowed_types`]
 +  [#7791](https://github.com/rust-lang/rust-clippy/pull/7791)
 +* Fix [`manual_assert`] and [`match_wild_err_arm`] for `#![no_std]` and Rust
 +  2021. [#7851](https://github.com/rust-lang/rust-clippy/pull/7851)
 +* Fix regression in [`semicolon_if_nothing_returned`] on macros containing while
 +  loops [#7789](https://github.com/rust-lang/rust-clippy/pull/7789)
 +* Added a new configuration `literal-suffix-style` to enforce a certain style
 +  writing [`unseparated_literal_suffix`]
 +  [#7726](https://github.com/rust-lang/rust-clippy/pull/7726)
 +
 +## Rust 1.57
 +
 +Released 2021-12-02
 +
 +[7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa)
 +
 +### New Lints
 +
 +* [`negative_feature_names`]
 +  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
 +* [`redundant_feature_names`]
 +  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
 +* [`mod_module_files`]
 +  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
 +* [`self_named_module_files`]
 +  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
 +* [`manual_split_once`]
 +  [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
 +* [`derivable_impls`]
 +  [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
 +* [`needless_option_as_deref`]
 +  [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
 +* [`iter_not_returning_iterator`]
 +  [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
 +* [`same_name_method`]
 +  [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
 +* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
 +* [`non_send_fields_in_send_ty`]
 +  [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
 +* [`equatable_if_let`]
 +  [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
 +
 +### Moves and Deprecations
 +
 +* Move [`shadow_unrelated`] to `restriction`
 +  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
 +* Move [`option_if_let_else`] to `nursery`
 +  [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
 +* Move [`branches_sharing_code`] to `nursery`
 +  [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
 +* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
 +  `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
 +* Move [`many_single_char_names`] to `pedantic`
 +  [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
 +* Move [`float_cmp`] to `pedantic`
 +  [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
 +* Rename `box_vec` to [`box_collection`] and lint on more general cases
 +  [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
 +* Uplift `invalid_atomic_ordering` to rustc
 +  [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
 +
 +### Enhancements
 +
 +* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
 +  limited to certain patterns
 +  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
 +* The `avoid-breaking-exported-api` configuration now also works for
 +  [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
 +  [`option_option`], [`linkedlist`], [`rc_mutex`]
 +  [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
 +* [`unnecessary_unwrap`]: Now also checks for `expect`s
 +  [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
 +* [`disallowed_methods`]: Allow adding a reason that will be displayed with the
 +  lint message
 +  [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
 +* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
 +  [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
 +* [`approx_constant`]: Add `TAU`
 +  [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
 +* [`needless_borrow`]: Now also lints on needless mutable borrows
 +  [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
 +* [`missing_safety_doc`]: Now also lints on unsafe traits
 +  [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
 +
 +### False Positive Fixes
 +
 +* [`manual_map`]: No longer lints when the option is borrowed in the match and
 +  also consumed in the arm
 +  [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
 +* [`filter_next`]: No longer lints if `filter` method is not the
 +  `Iterator::filter` method
 +  [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
 +* [`manual_flatten`]: No longer lints if expression is used after `if let`
 +  [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
 +* [`option_if_let_else`]: Multiple fixes
 +  [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
 +    * `break` and `continue` statements local to the would-be closure are
 +      allowed
 +    * Don't lint in const contexts
 +    * Don't lint when yield expressions are used
 +    * Don't lint when the captures made by the would-be closure conflict with
 +      the other branch
 +    * Don't lint when a field of a local is used when the type could be
 +      potentially moved from
 +    * In some cases, don't lint when scrutinee expression conflicts with the
 +      captures of the would-be closure
 +* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
 +  wide pointers with thin pointers
 +  [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
 +* [`bool_assert_comparison`]: No longer lints on types that do not implement the
 +  `Not` trait with `Output = bool`
 +  [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
 +* [`mut_range_bound`]: No longer lints on range bound mutations, that are
 +  immediately followed by a `break;`
 +  [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
 +* [`mutable_key_type`]: Improve accuracy and document remaining false positives
 +  and false negatives
 +  [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
 +* [`redundant_closure`]: Rewrite the lint to fix various false positives and
 +  false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
 +* [`large_enum_variant`]: No longer wrongly identifies the second largest
 +  variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
 +* [`needless_return`]: No longer lints on let-else expressions
 +  [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
 +* [`suspicious_else_formatting`]: No longer lints in proc-macros
 +  [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
 +* [`excessive_precision`]: No longer lints when in some cases the float was
 +  already written in the shortest form
 +  [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
 +* [`doc_markdown`]: No longer lints on intra-doc links
 +  [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
 +  function call in an indexing operation
 +  [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
 +* [`manual_split_once`]: Produce semantically equivalent suggestion when
 +  `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
 +* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
 +  [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
 +* [`manual_assert`]: No better handles complex conditions
 +  [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
 +* Correctly handle signs in exponents in numeric literals lints
 +  [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
 +* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
 +  [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
 +* Drop exponent from suggestion if it is 0 in numeric literals lints
 +  [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
 +
 +### ICE Fixes
 +
 +* [`implicit_hasher`]
 +  [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
 +
 +### Others
 +
 +* Clippy now uses the 2021
 +  [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
 +  [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
 +
 +## Rust 1.56
 +
 +Released 2021-10-21
 +
 +[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
 +
 +### New Lints
 +
 +* [`unwrap_or_else_default`]
 +  [#7516](https://github.com/rust-lang/rust-clippy/pull/7516)
 +
 +### Enhancements
 +
 +* [`needless_continue`]: Now also lints in `loop { continue; }` case
 +  [#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
 +* [`disallowed_types`]: Now also primitive types can be disallowed
 +  [#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
 +* [`manual_swap`]: Now also lints on xor swaps
 +  [#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
 +* [`map_flatten`]: Now also lints on the `Result` type
 +  [#7522](https://github.com/rust-lang/rust-clippy/pull/7522)
 +* [`no_effect`]: Now also lints on inclusive ranges
 +  [#7556](https://github.com/rust-lang/rust-clippy/pull/7556)
 +
 +### False Positive Fixes
 +
 +* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros
 +  [#7478](https://github.com/rust-lang/rust-clippy/pull/7478)
 +* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics
 +  [#7534](https://github.com/rust-lang/rust-clippy/pull/7534)
 +* [`similar_names`]: No longer complains about `iter` and `item` being too
 +  similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`similar_names`]: No longer suggests to insert or add an underscore as a fix
 +  [#7221](https://github.com/rust-lang/rust-clippy/pull/7221)
 +* [`new_without_default`]: No longer shows the full qualified type path when
 +  suggesting adding a `Default` implementation
 +  [#7493](https://github.com/rust-lang/rust-clippy/pull/7493)
 +* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references
 +  [#7520](https://github.com/rust-lang/rust-clippy/pull/7520)
 +* [`extend_with_drain`]: Improve code suggestion for mutable and immutable
 +  references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533)
 +* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type
 +  [#7535](https://github.com/rust-lang/rust-clippy/pull/7535)
 +* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when
 +  applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541)
 +
 +### Documentation Improvements
 +
 +* Clippy now uses a lint to generate its lint documentation. [Lints all the way
 +  down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
 +  [#7502](https://github.com/rust-lang/rust-clippy/pull/7502)
 +* Reworked Clippy's website:
 +  [#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
 +  [#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
 +  * Added applicability information about lints
 +  * Added a link to jump into the implementation
 +  * Improved loading times
 +  * Adapted some styling
 +* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag
 +  [#7492](https://github.com/rust-lang/rust-clippy/pull/7492)
 +* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
 +  example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
 +
 +## Rust 1.55
 +
 +Released 2021-09-09
 +
 +[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
 +
 +### Important Changes
 +
 +* Stabilized `cargo clippy --fix` :tada:
 +  [#7405](https://github.com/rust-lang/rust-clippy/pull/7405)
 +
 +### New Lints
 +
 +* [`rc_mutex`]
 +  [#7316](https://github.com/rust-lang/rust-clippy/pull/7316)
 +* [`nonstandard_macro_braces`]
 +  [#7299](https://github.com/rust-lang/rust-clippy/pull/7299)
 +* [`strlen_on_c_strings`]
 +  [#7243](https://github.com/rust-lang/rust-clippy/pull/7243)
 +* [`self_named_constructors`]
 +  [#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
 +* [`disallowed_script_idents`]
 +  [#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
 +* [`disallowed_types`]
 +  [#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
 +* [`missing_enforced_import_renames`]
 +  [#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
 +* [`extend_with_drain`]
 +  [#7270](https://github.com/rust-lang/rust-clippy/pull/7270)
 +
 +### Moves and Deprecations
 +
 +* Moved [`from_iter_instead_of_collect`] to `pedantic`
 +  [#7375](https://github.com/rust-lang/rust-clippy/pull/7375)
 +* Added `suspicious` as a new lint group for *code that is most likely wrong or useless*
 +  [#7350](https://github.com/rust-lang/rust-clippy/pull/7350)
 +  * Moved [`blanket_clippy_restriction_lints`] to `suspicious`
 +  * Moved [`empty_loop`] to `suspicious`
 +  * Moved [`eval_order_dependence`] to `suspicious`
 +  * Moved [`float_equality_without_abs`] to `suspicious`
 +  * Moved [`for_loops_over_fallibles`] to `suspicious`
 +  * Moved [`misrefactored_assign_op`] to `suspicious`
 +  * Moved [`mut_range_bound`] to `suspicious`
 +  * Moved [`mutable_key_type`] to `suspicious`
 +  * Moved [`suspicious_arithmetic_impl`] to `suspicious`
 +  * Moved [`suspicious_assignment_formatting`] to `suspicious`
 +  * Moved [`suspicious_else_formatting`] to `suspicious`
 +  * Moved [`suspicious_map`] to `suspicious`
 +  * Moved [`suspicious_op_assign_impl`] to `suspicious`
 +  * Moved [`suspicious_unary_op_formatting`] to `suspicious`
 +
 +### Enhancements
 +
 +* [`while_let_on_iterator`]: Now suggests `&mut iter` inside closures
 +  [#7262](https://github.com/rust-lang/rust-clippy/pull/7262)
 +* [`doc_markdown`]:
 +  * Now detects unbalanced ticks
 +    [#7357](https://github.com/rust-lang/rust-clippy/pull/7357)
 +  * Add `FreeBSD` to the default configuration as an allowed identifier
 +    [#7334](https://github.com/rust-lang/rust-clippy/pull/7334)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: Now allows wildcards for enums with unstable
 +  or hidden variants
 +  [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 +* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
 +  [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
 +* [`blacklisted_name`]: Now allows blacklisted names in test code
 +  [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 +* [`redundant_closure`]: Suggests `&mut` for `FnMut`
 +  [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
 +* [`disallowed_methods`], [`disallowed_types`]: The configuration values `disallowed-method` and `disallowed-type`
 +  no longer require fully qualified paths
 +  [#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
 +* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
 +  [#7396](https://github.com/rust-lang/rust-clippy/pull/7396)
 +
 +### False Positive Fixes
 +
 +* [`default_numeric_fallback`]: No longer lints on float literals as function arguments
 +  [#7446](https://github.com/rust-lang/rust-clippy/pull/7446)
 +* [`use_self`]: No longer lints on type parameters
 +  [#7288](https://github.com/rust-lang/rust-clippy/pull/7288)
 +* [`unimplemented`]: Now ignores the `assert` and `debug_assert` macros
 +  [#7439](https://github.com/rust-lang/rust-clippy/pull/7439)
 +* [`branches_sharing_code`]: Now always checks for block expressions
 +  [#7462](https://github.com/rust-lang/rust-clippy/pull/7462)
 +* [`field_reassign_with_default`]: No longer triggers in macros
 +  [#7160](https://github.com/rust-lang/rust-clippy/pull/7160)
 +* [`redundant_clone`]: No longer lints on required clones for borrowed data
 +  [#7346](https://github.com/rust-lang/rust-clippy/pull/7346)
 +* [`default_numeric_fallback`]: No longer triggers in external macros
 +  [#7325](https://github.com/rust-lang/rust-clippy/pull/7325)
 +* [`needless_bool`]: No longer lints in macros
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`useless_format`]: No longer triggers when additional text is being appended
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`assertions_on_constants`]: `cfg!(...)` is no longer considered to be a constant
 +  [#7319](https://github.com/rust-lang/rust-clippy/pull/7319)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`needless_collect`]: Now show correct lint messages for shadowed values
 +  [#7289](https://github.com/rust-lang/rust-clippy/pull/7289)
 +* [`wrong_pub_self_convention`]: The deprecated message now suggest the correct configuration value
 +  [#7382](https://github.com/rust-lang/rust-clippy/pull/7382)
 +* [`semicolon_if_nothing_returned`]: Allow missing semicolon in blocks with only one expression
 +  [#7326](https://github.com/rust-lang/rust-clippy/pull/7326)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#7470](https://github.com/rust-lang/rust-clippy/pull/7470)
 +* [`redundant_pattern_matching`]
 +  [#7471](https://github.com/rust-lang/rust-clippy/pull/7471)
 +* [`modulo_one`]
 +  [#7473](https://github.com/rust-lang/rust-clippy/pull/7473)
 +* [`use_self`]
 +  [#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
 +
 +## Rust 1.54
 +
 +Released 2021-07-29
 +
 +[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
 +
 +### New Lints
 +
 +- [`ref_binding_to_reference`]
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`needless_bitwise_bool`]
 +  [#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
 +- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
 +- [`manual_str_repeat`]
 +  [#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
 +- [`suspicious_splitn`]
 +  [#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
 +
 +### Moves and Deprecations
 +
 +- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
 +  the new `avoid-breaking-exported-api` config option (see
 +  [Enhancements](#1-54-enhancements))
 +  [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- Move [`inconsistent_struct_constructor`] to `pedantic`
 +  [#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
 +- Move [`needless_borrow`] to `style` (now warn-by-default)
 +  [#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
 +- Move [`suspicious_operation_groupings`] to `nursery`
 +  [#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
 +- Move [`semicolon_if_nothing_returned`] to `pedantic`
 +  [#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
 +
 +### Enhancements <a name="1-54-enhancements"></a>
 +
 +- [`while_let_on_iterator`]: Now also lints in nested loops
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
 +  [#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
 +- [`needless_collect`]: Now also lints on assignments with type annotations
 +  [#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
 +- [`if_then_some_else_none`]: Now works with the MSRV config
 +  [#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
 +- Add `avoid-breaking-exported-api` config option for the lints
 +  [`enum_variant_names`], [`large_types_passed_by_value`],
 +  [`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
 +  [`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
 +  this configuration option to `false` before a major release (1.0/2.0/...) to
 +  clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- [`needless_collect`]: Now lints on even more data structures
 +  [#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
 +- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
 +  attributes as sufficient documentation
 +  [#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
 +- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
 +  Now work as expected when used with `allow`
 +  [#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
 +
 +### False Positive Fixes
 +
 +- [`implicit_return`]: Now takes all diverging functions in account to avoid
 +  false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
 +  and the struct is used in the loop
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`multiple_inherent_impl`]: No longer lints with generic arguments
 +  [#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
 +- [`comparison_chain`]: No longer lints in a `const` context
 +  [#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
 +- [`while_immutable_condition`]: Fix false positive where mutation in the loop
 +  variable wasn't picked up
 +  [#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
 +- [`default_trait_access`]: No longer lints in macros
 +  [#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
 +- [`needless_question_mark`]: No longer lints when the inner value is implicitly
 +  dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
 +- [`unused_unit`]: No longer lints when multiple macro contexts are involved
 +  [#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
 +- [`eval_order_dependence`]: Fix false positive in async context
 +  [#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
 +- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
 +  type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
 +- [`wrong_self_convention`]: No longer lints in trait implementations of
 +  non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
 +- [`suboptimal_flops`]: No longer lints on `powi(2)`
 +  [#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
 +- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
 +  [#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
 +- [`option_if_let_else`]: No longer lints on `else if let` pattern
 +  [#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
 +- [`use_self`], [`useless_conversion`]: Fix false positives when generic
 +  arguments are involved
 +  [#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
 +- [`manual_unwrap_or`]: Fix false positive with deref coercion
 +  [#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
 +- [`similar_names`]: No longer lints on `wparam`/`lparam`
 +  [#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
 +- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
 +  closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
 +
 +### Suggestion Fixes/Improvements
 +
 +- [`implicit_return`]
 +  [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +    - Fix suggestion for async functions
 +    - Improve suggestion with macros
 +    - Suggest to change `break` to `return` when appropriate
 +- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`match_single_binding`]: Improve suggestion when match scrutinee has side
 +  effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
 +- [`needless_borrow`]: Now suggests to also change usage sites as needed
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
 +  buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
 +- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
 +  when a `<_ as Trait>::_` is involved
 +  [#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
 +- [`not_unsafe_ptr_arg_deref`]: Improved error message
 +  [#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
 +
 +### ICE Fixes
 +
 +- Fix ICE when running Clippy on `libstd`
 +  [#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
 +- [`implicit_return`]
 +  [#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
 +
 +## Rust 1.53
 +
 +Released 2021-06-17
 +
 +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
 +
 +### New Lints
 +
 +* [`option_filter_map`]
 +  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
 +* [`branches_sharing_code`]
 +  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
 +* [`needless_for_each`]
 +  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
 +* [`if_then_some_else_none`]
 +  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
 +* [`non_octal_unix_permissions`]
 +  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
 +* [`unnecessary_self_imports`]
 +  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
 +* [`bool_assert_comparison`]
 +  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
 +* [`cloned_instead_of_copied`]
 +  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
 +* [`flat_map_option`]
 +  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`filter_map`] lint
 +  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
 +* Move [`transmute_ptr_to_ptr`] to `pedantic`
 +  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
 +
 +### Enhancements
 +
 +* [`mem_replace_with_default`]: Also lint on common std constructors
 +  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
 +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
 +  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
 +  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
 +    * Attempt to find a common path prefix in suggestion
 +    * Don't lint on `Option` and `Result`
 +    * Consider `Self` prefix
 +* [`explicit_deref_methods`]: Also lint on chained `deref` calls
 +  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
 +* [`or_fun_call`]: Also lint on `unsafe` blocks
 +  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
 +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
 +  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
 +* [`search_is_some`]: Also check for `is_none`
 +  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
 +* [`string_lit_as_bytes`]: Also lint on `into_bytes`
 +  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
 +* [`len_without_is_empty`]: Also lint if function signatures of `len` and
 +  `is_empty` don't match
 +  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
 +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
 +  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
 +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
 +  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
 +* [`needless_return`]: Also lint in `async` functions
 +  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
 +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
 +  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
 +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
 +  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
 +
 +### False Positive Fixes
 +
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
 +* [`suspicious_map`]: No longer lints when side effects may occur inside the
 +  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
 +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
 +  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
 +* [`wrong_self_convention`]: Now respects `Copy` types
 +  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
 +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
 +  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
 +* [`map_entry`]: Better detect if the entry API can be used
 +  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`or_fun_call`]: No longer lints on some `len` function calls
 +  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
 +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
 +  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
 +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
 +  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
 +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
 +  suggesting to use `derive` instead
 +  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
 +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
 +  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
 +* [`clone_on_copy`]: Only lint when using the `Clone` trait
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`wrong_self_convention`]: No longer lints inside a trait implementation
 +  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
 +* [`redundant_clone`]: No longer lints when the cloned value is modified while
 +  the clone is in use
 +  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
 +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
 +  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
 +* [`cargo_common_metadata`]: Remove author requirement
 +  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
 +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
 +  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
 +* [`panic`]: No longer wrongfully lints on `debug_assert` with message
 +  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
 +* [`wrong_self_convention`]: No longer lints in trait implementations where no
 +  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
 +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
 +  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
 +* [`suspicious_else_formatting`]: Allow Allman style braces
 +  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
 +* [`inconsistent_struct_constructor`]: No longer lints in macros
 +  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
 +* [`single_component_path_imports`]: No longer lints on macro re-exports
 +  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`redundant_pattern_matching`]: Add a note when applying this lint would
 +  change the drop order
 +  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
 +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
 +  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
 +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
 +  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
 +* [`inconsistent_struct_constructor`]: Make lint description and message clearer
 +  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
 +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
 +  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`manual_flatten`]: Suggest to insert `copied` if necessary
 +  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
 +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
 +  when the value is from a macro call
 +  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
 +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
 +  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
 +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`manual_map`]: Fix suggestion at the end of an if chain
 +  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
 +* Fix needless parenthesis output in multiple lint suggestions
 +  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
 +* [`needless_collect`]: Better explanation in the lint message
 +  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
 +* [`useless_vec`]: Now considers mutability
 +  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
 +* [`useless_format`]: Wrap the content in braces if necessary
 +  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
 +* [`single_match`]: Don't suggest an equality check for types which don't
 +  implement `PartialEq`
 +  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
 +* [`from_over_into`]: Mention type in help message
 +  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
 +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
 +  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
 +
 +### ICE Fixes
 +
 +* [`macro_use_imports`]
 +  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
 +* [`missing_panics_doc`]
 +  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
 +* [`tabs_in_doc_comments`]
 +  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
 +* [`missing_const_for_fn`]
 +  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
 +  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
 +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
 +  deprecation warning
 +  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 +
 +## Rust 1.52
 +
 +Released 2021-05-06
 +
 +[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 +
 +### New Lints
 +
 +* [`from_str_radix_10`]
 +  [#6717](https://github.com/rust-lang/rust-clippy/pull/6717)
 +* [`implicit_clone`]
 +  [#6730](https://github.com/rust-lang/rust-clippy/pull/6730)
 +* [`semicolon_if_nothing_returned`]
 +  [#6681](https://github.com/rust-lang/rust-clippy/pull/6681)
 +* [`manual_flatten`]
 +  [#6646](https://github.com/rust-lang/rust-clippy/pull/6646)
 +* [`inconsistent_struct_constructor`]
 +  [#6769](https://github.com/rust-lang/rust-clippy/pull/6769)
 +* [`iter_count`]
 +  [#6791](https://github.com/rust-lang/rust-clippy/pull/6791)
 +* [`default_numeric_fallback`]
 +  [#6662](https://github.com/rust-lang/rust-clippy/pull/6662)
 +* [`bytes_nth`]
 +  [#6695](https://github.com/rust-lang/rust-clippy/pull/6695)
 +* [`filter_map_identity`]
 +  [#6685](https://github.com/rust-lang/rust-clippy/pull/6685)
 +* [`manual_map`]
 +  [#6573](https://github.com/rust-lang/rust-clippy/pull/6573)
 +
 +### Moves and Deprecations
 +
 +* Moved [`upper_case_acronyms`] to `pedantic`
 +  [#6775](https://github.com/rust-lang/rust-clippy/pull/6775)
 +* Moved [`manual_map`] to `nursery`
 +  [#6796](https://github.com/rust-lang/rust-clippy/pull/6796)
 +* Moved [`unnecessary_wraps`] to `pedantic`
 +  [#6765](https://github.com/rust-lang/rust-clippy/pull/6765)
 +* Moved [`trivial_regex`] to `nursery`
 +  [#6696](https://github.com/rust-lang/rust-clippy/pull/6696)
 +* Moved [`naive_bytecount`] to `pedantic`
 +  [#6825](https://github.com/rust-lang/rust-clippy/pull/6825)
 +* Moved [`upper_case_acronyms`] to `style`
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* Moved [`manual_map`] to `style`
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +
 +### Enhancements
 +
 +* [`disallowed_methods`]: Now supports functions in addition to methods
 +  [#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
 +* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
 +  trigger the lint if there is more than one uppercase character next to each other
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* [`collapsible_match`]: Now supports block comparison with different value names
 +  [#6754](https://github.com/rust-lang/rust-clippy/pull/6754)
 +* [`unnecessary_wraps`]: Will now suggest removing unnecessary wrapped return unit type, like `Option<()>`
 +  [#6665](https://github.com/rust-lang/rust-clippy/pull/6665)
 +* Improved value usage detection in closures
 +  [#6698](https://github.com/rust-lang/rust-clippy/pull/6698)
 +
 +### False Positive Fixes
 +
 +* [`use_self`]: No longer lints in macros
 +  [#6833](https://github.com/rust-lang/rust-clippy/pull/6833)
 +* [`use_self`]: Fixed multiple false positives for: generics, associated types and derive implementations
 +  [#6179](https://github.com/rust-lang/rust-clippy/pull/6179)
 +* [`missing_inline_in_public_items`]: No longer lints for procedural macros
 +  [#6814](https://github.com/rust-lang/rust-clippy/pull/6814)
 +* [`inherent_to_string`]: No longer lints on functions with function generics
 +  [#6771](https://github.com/rust-lang/rust-clippy/pull/6771)
 +* [`doc_markdown`]: Add `OpenDNS` to the default configuration as an allowed identifier
 +  [#6783](https://github.com/rust-lang/rust-clippy/pull/6783)
 +* [`missing_panics_doc`]: No longer lints on [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html)
 +  [#6700](https://github.com/rust-lang/rust-clippy/pull/6700)
 +* [`collapsible_if`]: No longer lints on if statements with attributes
 +  [#6701](https://github.com/rust-lang/rust-clippy/pull/6701)
 +* [`match_same_arms`]: Only considers empty blocks as equal if the tokens contained are the same
 +  [#6843](https://github.com/rust-lang/rust-clippy/pull/6843)
 +* [`redundant_closure`]: Now ignores macros
 +  [#6871](https://github.com/rust-lang/rust-clippy/pull/6871)
 +* [`manual_map`]: Fixed false positives when control flow statements like `return`, `break` etc. are used
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* [`vec_init_then_push`]: Fixed false positives for loops and if statements
 +  [#6697](https://github.com/rust-lang/rust-clippy/pull/6697)
 +* [`len_without_is_empty`]: Will now consider multiple impl blocks and `#[allow]` on
 +  the `len` method as well as the type definition.
 +  [#6853](https://github.com/rust-lang/rust-clippy/pull/6853)
 +* [`let_underscore_drop`]: Only lints on types which implement `Drop`
 +  [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 +* [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
 +  [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
 +* [`cargo_common_metadata`]: No longer lints if
 +  [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
 +  is defined in the manifest
 +  [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`collapsible_match`]: Fixed lint message capitalization
 +  [#6766](https://github.com/rust-lang/rust-clippy/pull/6766)
 +* [`or_fun_call`]: Improved suggestions for `or_insert(vec![])`
 +  [#6790](https://github.com/rust-lang/rust-clippy/pull/6790)
 +* [`manual_map`]: No longer expands macros in the suggestions
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* Aligned Clippy's lint messages with the rustc dev guide
 +  [#6787](https://github.com/rust-lang/rust-clippy/pull/6787)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6866](https://github.com/rust-lang/rust-clippy/pull/6866)
 +
 +### Documentation Improvements
 +
 +* [`useless_format`]: Improved the documentation example
 +  [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
 +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
 +  [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 +
 +### Others
 +* Running `cargo clippy` after `cargo check` now works as expected
 +  (`cargo clippy` and `cargo check` no longer shares the same build cache)
 +  [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 +* Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
 +  [#6834](https://github.com/rust-lang/rust-clippy/pull/6834)
 +* Extracted Clippy's `utils` module into the new `clippy_utils` crate
 +  [#6756](https://github.com/rust-lang/rust-clippy/pull/6756)
 +* Clippy lintcheck tool improvements
 +  [#6800](https://github.com/rust-lang/rust-clippy/pull/6800)
 +  [#6735](https://github.com/rust-lang/rust-clippy/pull/6735)
 +  [#6764](https://github.com/rust-lang/rust-clippy/pull/6764)
 +  [#6708](https://github.com/rust-lang/rust-clippy/pull/6708)
 +  [#6780](https://github.com/rust-lang/rust-clippy/pull/6780)
 +  [#6686](https://github.com/rust-lang/rust-clippy/pull/6686)
 +
 +## Rust 1.51
 +
 +Released 2021-03-25
 +
 +[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 +
 +### New Lints
 +
 +* [`upper_case_acronyms`]
 +  [#6475](https://github.com/rust-lang/rust-clippy/pull/6475)
 +* [`from_over_into`] [#6476](https://github.com/rust-lang/rust-clippy/pull/6476)
 +* [`case_sensitive_file_extension_comparisons`]
 +  [#6500](https://github.com/rust-lang/rust-clippy/pull/6500)
 +* [`needless_question_mark`]
 +  [#6507](https://github.com/rust-lang/rust-clippy/pull/6507)
 +* [`missing_panics_doc`]
 +  [#6523](https://github.com/rust-lang/rust-clippy/pull/6523)
 +* [`redundant_slicing`]
 +  [#6528](https://github.com/rust-lang/rust-clippy/pull/6528)
 +* [`vec_init_then_push`]
 +  [#6538](https://github.com/rust-lang/rust-clippy/pull/6538)
 +* [`ptr_as_ptr`] [#6542](https://github.com/rust-lang/rust-clippy/pull/6542)
 +* [`collapsible_else_if`] (split out from `collapsible_if`)
 +  [#6544](https://github.com/rust-lang/rust-clippy/pull/6544)
 +* [`inspect_for_each`] [#6577](https://github.com/rust-lang/rust-clippy/pull/6577)
 +* [`manual_filter_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* [`exhaustive_enums`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +* [`exhaustive_structs`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +
 +### Moves and Deprecations
 +
 +* Replace [`find_map`] with [`manual_find_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* `unknown_clippy_lints` Now integrated in the `unknown_lints` rustc lint
 +  [#6653](https://github.com/rust-lang/rust-clippy/pull/6653)
 +
 +### Enhancements
 +
 +* [`ptr_arg`] Now also suggests to use `&Path` instead of `&PathBuf`
 +  [#6506](https://github.com/rust-lang/rust-clippy/pull/6506)
 +* [`cast_ptr_alignment`] Also lint when the `pointer::cast` method is used
 +  [#6557](https://github.com/rust-lang/rust-clippy/pull/6557)
 +* [`collapsible_match`] Now also deals with `&` and `*` operators in the `match`
 +  scrutinee [#6619](https://github.com/rust-lang/rust-clippy/pull/6619)
 +
 +### False Positive Fixes
 +
 +* [`similar_names`] Ignore underscore prefixed names
 +  [#6403](https://github.com/rust-lang/rust-clippy/pull/6403)
 +* [`print_literal`] and [`write_literal`] No longer lint numeric literals
 +  [#6408](https://github.com/rust-lang/rust-clippy/pull/6408)
 +* [`large_enum_variant`] No longer lints in external macros
 +  [#6485](https://github.com/rust-lang/rust-clippy/pull/6485)
 +* [`empty_enum`] Only lint if `never_type` feature is enabled
 +  [#6513](https://github.com/rust-lang/rust-clippy/pull/6513)
 +* [`field_reassign_with_default`] No longer lints in macros
 +  [#6553](https://github.com/rust-lang/rust-clippy/pull/6553)
 +* [`size_of_in_element_count`] No longer lints when dividing by element size
 +  [#6578](https://github.com/rust-lang/rust-clippy/pull/6578)
 +* [`needless_return`] No longer lints in macros
 +  [#6586](https://github.com/rust-lang/rust-clippy/pull/6586)
 +* [`match_overlapping_arm`] No longer lint when first arm is completely included
 +  in second arm [#6603](https://github.com/rust-lang/rust-clippy/pull/6603)
 +* [`doc_markdown`] Add `WebGL` to the default configuration as an allowed
 +  identifier [#6605](https://github.com/rust-lang/rust-clippy/pull/6605)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`field_reassign_with_default`] Don't expand macro in lint suggestion
 +  [#6531](https://github.com/rust-lang/rust-clippy/pull/6531)
 +* [`match_like_matches_macro`] Strip references in suggestion
 +  [#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
 +* [`single_match`] Suggest `if` over `if let` when possible
 +  [#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
 +* `ref_in_deref` Use parentheses correctly in suggestion
 +  [#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
 +* [`stable_sort_primitive`] Clarify error message
 +  [#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6582](https://github.com/rust-lang/rust-clippy/pull/6582)
 +
 +### Documentation Improvements
 +
 +* Improve search performance on the Clippy website and make it possible to
 +  directly search for lints on the GitHub issue tracker
 +  [#6483](https://github.com/rust-lang/rust-clippy/pull/6483)
 +* Clean up `README.md` by removing outdated paragraph
 +  [#6488](https://github.com/rust-lang/rust-clippy/pull/6488)
 +* [`await_holding_refcell_ref`] and [`await_holding_lock`]
 +  [#6585](https://github.com/rust-lang/rust-clippy/pull/6585)
 +* [`as_conversions`] [#6608](https://github.com/rust-lang/rust-clippy/pull/6608)
 +
 +### Others
 +
 +* Clippy now has a [Roadmap] for 2021. If you like to get involved in a bigger
 +  project, take a look at the [Roadmap project page]. All issues listed there
 +  are actively mentored
 +  [#6462](https://github.com/rust-lang/rust-clippy/pull/6462)
 +* The Clippy version number now corresponds to the Rust version number
 +  [#6526](https://github.com/rust-lang/rust-clippy/pull/6526)
 +* Fix oversight which caused Clippy to lint deps in some environments, where
 +  `CLIPPY_TESTS=true` was set somewhere
 +  [#6575](https://github.com/rust-lang/rust-clippy/pull/6575)
 +* Add `cargo dev-lintcheck` tool to the Clippy Dev Tool
 +  [#6469](https://github.com/rust-lang/rust-clippy/pull/6469)
 +
 +[Roadmap]: https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md
 +[Roadmap project page]: https://github.com/rust-lang/rust-clippy/projects/3
 +
 +## Rust 1.50
 +
 +Released 2021-02-11
 +
 +[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
 +
 +### New Lints
 +
 +* [`suspicious_operation_groupings`] [#6086](https://github.com/rust-lang/rust-clippy/pull/6086)
 +* [`size_of_in_element_count`] [#6394](https://github.com/rust-lang/rust-clippy/pull/6394)
 +* [`unnecessary_wraps`] [#6070](https://github.com/rust-lang/rust-clippy/pull/6070)
 +* [`let_underscore_drop`] [#6305](https://github.com/rust-lang/rust-clippy/pull/6305)
 +* [`collapsible_match`] [#6402](https://github.com/rust-lang/rust-clippy/pull/6402)
 +* [`redundant_else`] [#6330](https://github.com/rust-lang/rust-clippy/pull/6330)
 +* [`zero_sized_map_values`] [#6218](https://github.com/rust-lang/rust-clippy/pull/6218)
 +* [`print_stderr`] [#6367](https://github.com/rust-lang/rust-clippy/pull/6367)
 +* [`string_from_utf8_as_bytes`] [#6134](https://github.com/rust-lang/rust-clippy/pull/6134)
 +
 +### Moves and Deprecations
 +
 +* Previously deprecated [`str_to_string`] and [`string_to_string`] have been un-deprecated
 +  as `restriction` lints [#6333](https://github.com/rust-lang/rust-clippy/pull/6333)
 +* Deprecate `panic_params` lint. This is now available in rustc as `non_fmt_panics`
 +  [#6351](https://github.com/rust-lang/rust-clippy/pull/6351)
 +* Move [`map_err_ignore`] to `restriction`
 +  [#6416](https://github.com/rust-lang/rust-clippy/pull/6416)
 +* Move [`await_holding_refcell_ref`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +* Move [`await_holding_lock`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +
 +### Enhancements
 +
 +* Add the `unreadable-literal-lint-fractions` configuration to disable
 +  the `unreadable_literal` lint for fractions
 +  [#6421](https://github.com/rust-lang/rust-clippy/pull/6421)
 +* [`clone_on_copy`]: Now shows the type in the lint message
 +  [#6443](https://github.com/rust-lang/rust-clippy/pull/6443)
 +* [`redundant_pattern_matching`]: Now also lints on `std::task::Poll`
 +  [#6339](https://github.com/rust-lang/rust-clippy/pull/6339)
 +* [`redundant_pattern_matching`]: Additionally also lints on `std::net::IpAddr`
 +  [#6377](https://github.com/rust-lang/rust-clippy/pull/6377)
 +* [`search_is_some`]: Now suggests `contains` instead of `find(foo).is_some()`
 +  [#6119](https://github.com/rust-lang/rust-clippy/pull/6119)
 +* [`clone_double_ref`]: Now prints the reference type in the lint message
 +  [#6442](https://github.com/rust-lang/rust-clippy/pull/6442)
 +* [`modulo_one`]: Now also lints on -1.
 +  [#6360](https://github.com/rust-lang/rust-clippy/pull/6360)
 +* [`empty_loop`]: Now lints no_std crates, too
 +  [#6205](https://github.com/rust-lang/rust-clippy/pull/6205)
 +* [`or_fun_call`]: Now also lints when indexing `HashMap` or `BTreeMap`
 +  [#6267](https://github.com/rust-lang/rust-clippy/pull/6267)
 +* [`wrong_self_convention`]: Now also lints in trait definitions
 +  [#6316](https://github.com/rust-lang/rust-clippy/pull/6316)
 +* [`needless_borrow`]: Print the type in the lint message
 +  [#6449](https://github.com/rust-lang/rust-clippy/pull/6449)
 +
 +[msrv_readme]: https://github.com/rust-lang/rust-clippy#specifying-the-minimum-supported-rust-version
 +
 +### False Positive Fixes
 +
 +* [`manual_range_contains`]: No longer lints in `const fn`
 +  [#6382](https://github.com/rust-lang/rust-clippy/pull/6382)
 +* [`unnecessary_lazy_evaluations`]: No longer lints if closure argument is used
 +  [#6370](https://github.com/rust-lang/rust-clippy/pull/6370)
 +* [`match_single_binding`]: Now ignores cases with `#[cfg()]` macros
 +  [#6435](https://github.com/rust-lang/rust-clippy/pull/6435)
 +* [`match_like_matches_macro`]: No longer lints on arms with attributes
 +  [#6290](https://github.com/rust-lang/rust-clippy/pull/6290)
 +* [`map_clone`]: No longer lints with deref and clone
 +  [#6269](https://github.com/rust-lang/rust-clippy/pull/6269)
 +* [`map_clone`]: No longer lints in the case of &mut
 +  [#6301](https://github.com/rust-lang/rust-clippy/pull/6301)
 +* [`needless_update`]: Now ignores `non_exhaustive` structs
 +  [#6464](https://github.com/rust-lang/rust-clippy/pull/6464)
 +* [`needless_collect`]: No longer lints when a collect is needed multiple times
 +  [#6313](https://github.com/rust-lang/rust-clippy/pull/6313)
 +* [`unnecessary_cast`] No longer lints cfg-dependent types
 +  [#6369](https://github.com/rust-lang/rust-clippy/pull/6369)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
 +  Both now ignore enums with frozen variants
 +  [#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
 +* [`field_reassign_with_default`] No longer lint for private fields
 +  [#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
 +
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`vec_box`]: Provide correct type scope suggestion
 +  [#6271](https://github.com/rust-lang/rust-clippy/pull/6271)
 +* [`manual_range_contains`]: Give correct suggestion when using floats
 +  [#6320](https://github.com/rust-lang/rust-clippy/pull/6320)
 +* [`unnecessary_lazy_evaluations`]: Don't always mark suggestion as MachineApplicable
 +  [#6272](https://github.com/rust-lang/rust-clippy/pull/6272)
 +* [`manual_async_fn`]: Improve suggestion formatting
 +  [#6294](https://github.com/rust-lang/rust-clippy/pull/6294)
 +* [`unnecessary_cast`]: Fix incorrectly formatted float literal suggestion
 +  [#6362](https://github.com/rust-lang/rust-clippy/pull/6362)
 +
 +### ICE Fixes
 +
 +* Fix a crash in [`from_iter_instead_of_collect`]
 +  [#6304](https://github.com/rust-lang/rust-clippy/pull/6304)
 +* Fix a silent crash when parsing doc comments in [`needless_doctest_main`]
 +  [#6458](https://github.com/rust-lang/rust-clippy/pull/6458)
 +
 +### Documentation Improvements
 +
 +* The lint website search has been improved ([#6477](https://github.com/rust-lang/rust-clippy/pull/6477)):
 +  * Searching for lints with dashes and spaces is possible now. For example
 +    `missing-errors-doc` and `missing errors doc` are now valid aliases for lint names
 +  * Improved fuzzy search in lint descriptions
 +* Various README improvements
 +  [#6287](https://github.com/rust-lang/rust-clippy/pull/6287)
 +* Add known problems to [`comparison_chain`] documentation
 +  [#6390](https://github.com/rust-lang/rust-clippy/pull/6390)
 +* Fix example used in [`cargo_common_metadata`]
 +  [#6293](https://github.com/rust-lang/rust-clippy/pull/6293)
 +* Improve [`map_clone`] documentation
 +  [#6340](https://github.com/rust-lang/rust-clippy/pull/6340)
 +
 +### Others
 +
 +* You can now tell Clippy about the MSRV your project supports. Please refer to
 +  the specific README section to learn more about MSRV support [here][msrv_readme]
 +  [#6201](https://github.com/rust-lang/rust-clippy/pull/6201)
 +* Add `--no-deps` option to avoid running on path dependencies in workspaces
 +  [#6188](https://github.com/rust-lang/rust-clippy/pull/6188)
 +
 +## Rust 1.49
 +
 +Released 2020-12-31
 +
 +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 +
 +### New Lints
 +
 +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
 +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
 +* [`disallowed_methods`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
 +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
 +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
 +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
 +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
 +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
 +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
 +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
 +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
 +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
 +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
 +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
 +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
 +
 +### Moves and Deprecations
 +
 +* Rename `single_char_push_str` to [`single_char_add_str`]
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* Rename `zero_width_space` to [`invisible_characters`]
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* Deprecate `drop_bounds` (uplifted)
 +  [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
 +* Move [`string_lit_as_bytes`] to `nursery`
 +  [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
 +* Move [`rc_buffer`] to `restriction`
 +  [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
 +
 +### Enhancements
 +
 +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
 +  reliable suggestion)
 +  [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
 +* [`single_char_add_str`]: Also lint on `String::insert_str`
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* [`eq_op`]: Also lint on the `assert_*!` macro family
 +  [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
 +* [`items_after_statements`]: Also lint in local macro expansions
 +  [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
 +* [`unnecessary_cast`]: Also lint casts on integer and float literals
 +  [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
 +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
 +  [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
 +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
 +  [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
 +* [`integer_arithmetic`]: Better handle `/` an `%` operators
 +  [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
 +
 +### False Positive Fixes
 +
 +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
 +  lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
 +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
 +  is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
 +* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
 +  [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
 +* [`needless_range_loop`]: No longer lints, when the iterable is used in the
 +  range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
 +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
 +  [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
 +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
 +  float (e.g. `713.32_64`)
 +  [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
 +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
 +  [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
 +* [`boxed_local`]: No longer lints on `extern fn` arguments
 +  [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
 +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
 +  clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
 +  [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
 +* [`needless_arbitrary_self_type`]: Correctly handle expanded code
 +  [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
 +* [`useless_format`]: Preserve raw strings in suggestion
 +  [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
 +* [`empty_loop`]: Suggest alternatives
 +  [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`borrowed_box`]: Correctly add parentheses in suggestion
 +  [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
 +* [`unused_unit`]: Improve suggestion formatting
 +  [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
 +
 +### Documentation Improvements
 +
 +* Some doc improvements:
 +    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
 +    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`doc_markdown`]: Document problematic link text style
 +  [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 +
 +## Rust 1.48
 +
 +Released 2020-11-19
 +
 +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 +
 +### New lints
 +
 +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
 +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
 +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
 +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 +* `to_string_in_display` [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
 +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`verbose_bit_mask`] to pedantic
 +  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
 +
 +### Enhancements
 +
 +* Extend [`precedence`] to handle chains of methods combined with unary negation
 +  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
 +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
 +  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
 +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
 +  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
 +* `invalid_atomic_ordering`: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
 +  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
 +* Avoid [`redundant_pattern_matching`] triggering in macros
 +  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
 +* [`option_if_let_else`]: distinguish pure from impure `else` expressions
 +  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
 +* [`needless_doctest_main`]: parse doctests instead of using textual search
 +  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
 +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
 +  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
 +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
 +  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
 +
 +### False Positive Fixes
 +
 +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
 +  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
 +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
 +  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
 +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
 +  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
 +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
 +  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
 +* [`doc_markdown`]: allow using "GraphQL" without backticks
 +  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
 +* `to_string_in_display`: avoid linting when calling `to_string()` on anything that is not `self`
 +  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
 +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
 +  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
 +* [`should_implement_trait`]: ignore methods with lifetime parameters
 +  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
 +* [`needless_return`]: avoid linting if a temporary borrows a local variable
 +  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
 +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
 +  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
 +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
 +  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
 +  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
 +  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
 +* [`useless_conversion`]: show the type in the error message
 +  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
 +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
 +  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
 +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
 +  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
 +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
 +  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
 +* [`collapsible_if`]: don't use expanded code in the suggestion
 +  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
 +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
 +  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
 +* [`unit_arg`]: improve the readability of the suggestion
 +  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
 +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
 +  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
 +* Show line count and max lines in [`too_many_lines`] lint message
 +  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
 +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
 +  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
 +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
 +  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
 +* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
 +  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
 +* Make lint messages adhere to rustc dev guide conventions
 +  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`repeat_once`]
 +  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
 +
 +### Documentation Improvements
 +
 +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
 +  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
 +* [`unnecessary_mut_passed`]: fix typo
 +  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
 +* Add example of false positive to [`ptr_arg`] docs.
 +  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
 +* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
 +  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 +
 +## Rust 1.47
 +
 +Released 2020-10-08
 +
 +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 +
 +### New lints
 +
 +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
 +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
 +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
 +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
 +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
 +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
 +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
 +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
 +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
 +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
 +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
 +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`regex_macro`] lint
 +  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
 +* Move [`range_minus_one`] to `pedantic`
 +  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
 +
 +### Enhancements
 +
 +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
 +  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
 +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
 +  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
 +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
 +  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
 +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
 +  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
 +* Make it possible to allow [`unsafe_derive_deserialize`]
 +  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
 +* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
 +  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
 +* Make [`clone_on_copy`] suggestion machine applicable
 +  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
 +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +
 +### False Positive Fixes
 +
 +* Avoid triggering [`or_fun_call`] with const fns that take no arguments
 +  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
 +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
 +  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
 +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
 +  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
 +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
 +  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
 +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
 +  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
 +* Avoid linting if key borrows in [`unnecessary_sort_by`]
 +  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
 +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
 +  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
 +* Take input lifetimes into account in `manual_async_fn`
 +  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
 +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
 +  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
 +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
 +  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
 +  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
 +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
 +  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
 +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
 +  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
 +* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
 +  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
 +* Add suggestion for [`iter_skip_next`]
 +  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
 +* Improve [`collapsible_if`] fix suggestion
 +  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused by [`needless_collect`]
 +  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
 +* Fix ICE caused by [`unnested_or_patterns`]
 +  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
 +
 +### Documentation Improvements
 +
 +* Fix grammar of [`await_holding_lock`] documentation
 +  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
 +
 +### Others
 +
 +* Make lints adhere to the rustc dev guide
 +  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 +
 +## Rust 1.46
 +
 +Released 2020-08-27
 +
 +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 +
 +### New lints
 +
 +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
 +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
 +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
 +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
 +
 +### Moves and Deprecations
 +
 +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
 +
 +### Enhancements
 +
 +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
 +
 +### False Positive Fixes
 +
 +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
 +  [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
 +* [`let_and_return`]: Don't lint if a temporary borrow is involved
 +  [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
 +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
 +  [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 +* [`if_same_then_else`]: Don't assume multiplication is always commutative
 +  [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
 +* [`blacklisted_name`]: Remove `bar` from the default configuration
 +  [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
 +  [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
 +  [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
 +* Add auto applicable suggestion to [`macro_use_imports`]
 +  [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
 +
 +### ICE Fixes
 +
 +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
 +
 +### Documentation Improvements
 +
 +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
 +
 +### Others
 +
 +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
 +  into `rustc` and passes all the given arguments to `rustc`. This is especially
 +  useful for tools that need the `rustc` version Clippy was compiled with,
 +  instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
 +  print the output of `rustc --version`.
 +  [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
 +* New issue templates now make it easier to complain if Clippy is too annoying
 +  or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
 +
 +## Rust 1.45
 +
 +Released 2020-07-16
 +
 +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 +
 +### New lints
 +
 +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
 +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
 +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
 +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
 +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
 +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
 +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
 +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
 +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
 +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
 +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
 +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
 +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
 +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +
 +### Enhancements
 +
 +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
 +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
 +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
 +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
 +
 +### False Positive Fixes
 +
 +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
 +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
 +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
 +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
 +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
 +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
 +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
 +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
 +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
 +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
 +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
 +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
 +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
 +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
 +
 +### Suggestion Improvements
 +
 +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
 +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
 +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
 +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
 +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
 +
 +### Documentation
 +
 +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
 +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 +
 +## Rust 1.44
 +
 +Released 2020-06-04
 +
 +[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 +
 +### New lints
 +
 +* [`explicit_deref_methods`] [#5226](https://github.com/rust-lang/rust-clippy/pull/5226)
 +* [`implicit_saturating_sub`] [#5427](https://github.com/rust-lang/rust-clippy/pull/5427)
 +* [`macro_use_imports`] [#5230](https://github.com/rust-lang/rust-clippy/pull/5230)
 +* [`verbose_file_reads`] [#5272](https://github.com/rust-lang/rust-clippy/pull/5272)
 +* [`future_not_send`] [#5423](https://github.com/rust-lang/rust-clippy/pull/5423)
 +* [`redundant_pub_crate`] [#5319](https://github.com/rust-lang/rust-clippy/pull/5319)
 +* [`large_const_arrays`] [#5248](https://github.com/rust-lang/rust-clippy/pull/5248)
 +* [`result_map_or_into_option`] [#5415](https://github.com/rust-lang/rust-clippy/pull/5415)
 +* [`redundant_allocation`] [#5349](https://github.com/rust-lang/rust-clippy/pull/5349)
 +* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
 +* Move [`cognitive_complexity`] to nursery [#5428](https://github.com/rust-lang/rust-clippy/pull/5428)
 +* Move [`useless_transmute`] to nursery [#5364](https://github.com/rust-lang/rust-clippy/pull/5364)
 +* Downgrade [`inefficient_to_string`] to pedantic [#5412](https://github.com/rust-lang/rust-clippy/pull/5412)
 +* Downgrade [`option_option`] to pedantic [#5401](https://github.com/rust-lang/rust-clippy/pull/5401)
 +* Downgrade [`unreadable_literal`] to pedantic [#5419](https://github.com/rust-lang/rust-clippy/pull/5419)
 +* Downgrade [`let_unit_value`] to pedantic [#5409](https://github.com/rust-lang/rust-clippy/pull/5409)
 +* Downgrade [`trivially_copy_pass_by_ref`] to pedantic [#5410](https://github.com/rust-lang/rust-clippy/pull/5410)
 +* Downgrade [`implicit_hasher`] to pedantic [#5411](https://github.com/rust-lang/rust-clippy/pull/5411)
 +
 +### Enhancements
 +
 +* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
 +  auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 +* Make [`redundant_clone`] also trigger on cases where the cloned value is not
 +  consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
 +* Expand [`integer_arithmetic`] to also disallow bit-shifting [#5430](https://github.com/rust-lang/rust-clippy/pull/5430)
 +* [`option_as_ref_deref`] now detects more deref cases [#5425](https://github.com/rust-lang/rust-clippy/pull/5425)
 +* [`large_enum_variant`] now report the sizes of the largest and second-largest variants [#5466](https://github.com/rust-lang/rust-clippy/pull/5466)
 +* [`bool_comparison`] now also checks for inequality comparisons that can be
 +  written more concisely [#5365](https://github.com/rust-lang/rust-clippy/pull/5365)
 +* Expand [`clone_on_copy`] to work in method call arguments as well [#5441](https://github.com/rust-lang/rust-clippy/pull/5441)
 +* [`redundant_pattern_matching`] now also handles `while let` [#5483](https://github.com/rust-lang/rust-clippy/pull/5483)
 +* [`integer_arithmetic`] now also lints references of integers [#5329](https://github.com/rust-lang/rust-clippy/pull/5329)
 +* Expand [`float_cmp_const`] to also work on arrays [#5345](https://github.com/rust-lang/rust-clippy/pull/5345)
 +* Trigger [`map_flatten`] when map is called on an `Option` [#5473](https://github.com/rust-lang/rust-clippy/pull/5473)
 +
 +### False Positive Fixes
 +
 +* [`many_single_char_names`] [#5468](https://github.com/rust-lang/rust-clippy/pull/5468)
 +* [`should_implement_trait`] [#5437](https://github.com/rust-lang/rust-clippy/pull/5437)
 +* [`unused_self`] [#5387](https://github.com/rust-lang/rust-clippy/pull/5387)
 +* [`redundant_clone`] [#5453](https://github.com/rust-lang/rust-clippy/pull/5453)
 +* [`precedence`] [#5445](https://github.com/rust-lang/rust-clippy/pull/5445)
 +* [`suspicious_op_assign_impl`] [#5424](https://github.com/rust-lang/rust-clippy/pull/5424)
 +* [`needless_lifetimes`] [#5293](https://github.com/rust-lang/rust-clippy/pull/5293)
 +* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 +* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 +
 +
 +### Suggestion Improvements
 +
 +* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
 +* Improve the suggested placeholder in [`option_map_unit_fn`] [#5292](https://github.com/rust-lang/rust-clippy/pull/5292)
 +* Improve suggestion for [`match_single_binding`] when triggered inside a closure [#5350](https://github.com/rust-lang/rust-clippy/pull/5350)
 +
 +### ICE Fixes
 +
 +* Handle the unstable `trivial_bounds` feature [#5296](https://github.com/rust-lang/rust-clippy/pull/5296)
 +* `shadow_*` lints [#5297](https://github.com/rust-lang/rust-clippy/pull/5297)
 +
 +### Documentation
 +
 +* Fix documentation generation for configurable lints [#5353](https://github.com/rust-lang/rust-clippy/pull/5353)
 +* Update documentation for [`new_ret_no_self`] [#5448](https://github.com/rust-lang/rust-clippy/pull/5448)
 +* The documentation for [`option_option`] now suggest using a tri-state enum [#5403](https://github.com/rust-lang/rust-clippy/pull/5403)
 +* Fix bit mask example in [`verbose_bit_mask`] documentation [#5454](https://github.com/rust-lang/rust-clippy/pull/5454)
 +* [`wildcard_imports`] documentation now mentions that `use ...::prelude::*` is
 +  not linted [#5312](https://github.com/rust-lang/rust-clippy/pull/5312)
 +
 +## Rust 1.43
 +
 +Released 2020-04-23
 +
 +[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 +
 +### New lints
 +
 +* [`imprecise_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`suboptimal_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`wildcard_imports`] [#5029](https://github.com/rust-lang/rust-clippy/pull/5029)
 +* [`single_component_path_imports`] [#5058](https://github.com/rust-lang/rust-clippy/pull/5058)
 +* [`match_single_binding`] [#5061](https://github.com/rust-lang/rust-clippy/pull/5061)
 +* [`let_underscore_lock`] [#5101](https://github.com/rust-lang/rust-clippy/pull/5101)
 +* [`struct_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`fn_params_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`option_env_unwrap`] [#5148](https://github.com/rust-lang/rust-clippy/pull/5148)
 +* [`lossy_float_literal`] [#5202](https://github.com/rust-lang/rust-clippy/pull/5202)
 +* [`rest_pat_in_fully_bound_structs`] [#5258](https://github.com/rust-lang/rust-clippy/pull/5258)
 +
 +### Moves and Deprecations
 +
 +* Move [`unneeded_field_pattern`] to pedantic group [#5200](https://github.com/rust-lang/rust-clippy/pull/5200)
 +
 +### Enhancements
 +
 +* Make [`missing_errors_doc`] lint also trigger on `async` functions
 +  [#5181](https://github.com/rust-lang/rust-clippy/pull/5181)
 +* Add more constants to [`approx_constant`] [#5193](https://github.com/rust-lang/rust-clippy/pull/5193)
 +* Extend [`question_mark`] lint [#5266](https://github.com/rust-lang/rust-clippy/pull/5266)
 +
 +### False Positive Fixes
 +
 +* [`use_debug`] [#5047](https://github.com/rust-lang/rust-clippy/pull/5047)
 +* [`unnecessary_unwrap`] [#5132](https://github.com/rust-lang/rust-clippy/pull/5132)
 +* [`zero_prefixed_literal`] [#5170](https://github.com/rust-lang/rust-clippy/pull/5170)
 +* [`missing_const_for_fn`] [#5216](https://github.com/rust-lang/rust-clippy/pull/5216)
 +
 +### Suggestion Improvements
 +
 +* Improve suggestion when blocks of code are suggested [#5134](https://github.com/rust-lang/rust-clippy/pull/5134)
 +
 +### ICE Fixes
 +
 +* `misc_early` lints [#5129](https://github.com/rust-lang/rust-clippy/pull/5129)
 +* [`missing_errors_doc`] [#5213](https://github.com/rust-lang/rust-clippy/pull/5213)
 +* Fix ICE when evaluating `usize`s [#5256](https://github.com/rust-lang/rust-clippy/pull/5256)
 +
 +### Documentation
 +
 +* Improve documentation of [`iter_nth_zero`]
 +* Add documentation pages for stable releases [#5171](https://github.com/rust-lang/rust-clippy/pull/5171)
 +
 +### Others
 +
 +* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 +
 +
 +## Rust 1.42
 +
 +Released 2020-03-12
 +
 +[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206)
 +
 +### New lints
 +
 +* [`filetype_is_file`] [#4543](https://github.com/rust-lang/rust-clippy/pull/4543)
 +* [`let_underscore_must_use`] [#4823](https://github.com/rust-lang/rust-clippy/pull/4823)
 +* [`modulo_arithmetic`] [#4867](https://github.com/rust-lang/rust-clippy/pull/4867)
 +* [`mem_replace_with_default`] [#4881](https://github.com/rust-lang/rust-clippy/pull/4881)
 +* [`mutable_key_type`] [#4885](https://github.com/rust-lang/rust-clippy/pull/4885)
 +* [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945)
 +* [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960)
 +* [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966)
 +* `invalid_atomic_ordering` [#4999](https://github.com/rust-lang/rust-clippy/pull/4999)
 +* [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067)
 +
 +### Moves and Deprecations
 +
 +* Move [`transmute_float_to_int`] from nursery to complexity group
 +  [#5015](https://github.com/rust-lang/rust-clippy/pull/5015)
 +* Move [`range_plus_one`] to pedantic group [#5057](https://github.com/rust-lang/rust-clippy/pull/5057)
 +* Move [`debug_assert_with_mut_call`] to nursery group [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Deprecate `unused_label` [#4930](https://github.com/rust-lang/rust-clippy/pull/4930)
 +
 +### Enhancements
 +
 +* Lint vectored IO in [`unused_io_amount`] [#5027](https://github.com/rust-lang/rust-clippy/pull/5027)
 +* Make [`vec_box`] configurable by adding a size threshold [#5081](https://github.com/rust-lang/rust-clippy/pull/5081)
 +* Also lint constants in [`cmp_nan`] [#4910](https://github.com/rust-lang/rust-clippy/pull/4910)
 +* Fix false negative in [`expect_fun_call`] [#4915](https://github.com/rust-lang/rust-clippy/pull/4915)
 +* Fix false negative in [`redundant_clone`] [#5017](https://github.com/rust-lang/rust-clippy/pull/5017)
 +
 +### False Positive Fixes
 +
 +* [`map_clone`] [#4937](https://github.com/rust-lang/rust-clippy/pull/4937)
 +* [`replace_consts`] [#4977](https://github.com/rust-lang/rust-clippy/pull/4977)
 +* [`let_and_return`] [#5008](https://github.com/rust-lang/rust-clippy/pull/5008)
 +* [`eq_op`] [#5079](https://github.com/rust-lang/rust-clippy/pull/5079)
 +* [`possible_missing_comma`] [#5083](https://github.com/rust-lang/rust-clippy/pull/5083)
 +* [`debug_assert_with_mut_call`] [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Don't trigger [`let_underscore_must_use`] in external macros
 +  [#5082](https://github.com/rust-lang/rust-clippy/pull/5082)
 +* Don't trigger [`empty_loop`] in `no_std` crates [#5086](https://github.com/rust-lang/rust-clippy/pull/5086)
 +
 +### Suggestion Improvements
 +
 +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634)
 +* [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934)
 +* [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935)
 +* [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956)
 +* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
 +* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
 +* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
 +* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
 +
 +### ICE fixes
 +
 +* [`unsound_collection_transmute`] [#4975](https://github.com/rust-lang/rust-clippy/pull/4975)
 +
 +### Documentation
 +
 +* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 +
 +
 +## Rust 1.41
 +
 +Released 2020-01-30
 +
 +[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7)
 +
 +* New Lints:
 +  * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
 +  * [`to_digit_is_some`] [#4801](https://github.com/rust-lang/rust-clippy/pull/4801)
 +  * [`tabs_in_doc_comments`] [#4806](https://github.com/rust-lang/rust-clippy/pull/4806)
 +  * [`large_stack_arrays`] [#4807](https://github.com/rust-lang/rust-clippy/pull/4807)
 +  * [`same_functions_in_if_condition`] [#4814](https://github.com/rust-lang/rust-clippy/pull/4814)
 +  * [`zst_offset`] [#4816](https://github.com/rust-lang/rust-clippy/pull/4816)
 +  * [`as_conversions`] [#4821](https://github.com/rust-lang/rust-clippy/pull/4821)
 +  * [`missing_errors_doc`] [#4884](https://github.com/rust-lang/rust-clippy/pull/4884)
 +  * [`transmute_float_to_int`] [#4889](https://github.com/rust-lang/rust-clippy/pull/4889)
 +* Remove plugin interface, see
 +  [Inside Rust Blog](https://blog.rust-lang.org/inside-rust/2019/11/04/Clippy-removes-plugin-interface.html) for
 +  details [#4714](https://github.com/rust-lang/rust-clippy/pull/4714)
 +* Move [`use_self`] to nursery group [#4863](https://github.com/rust-lang/rust-clippy/pull/4863)
 +* Deprecate `into_iter_on_array` [#4788](https://github.com/rust-lang/rust-clippy/pull/4788)
 +* Expand [`string_lit_as_bytes`] to also trigger when literal has escapes
 +  [#4808](https://github.com/rust-lang/rust-clippy/pull/4808)
 +* Fix false positive in `comparison_chain` [#4842](https://github.com/rust-lang/rust-clippy/pull/4842)
 +* Fix false positive in `while_immutable_condition` [#4730](https://github.com/rust-lang/rust-clippy/pull/4730)
 +* Fix false positive in `explicit_counter_loop` [#4803](https://github.com/rust-lang/rust-clippy/pull/4803)
 +* Fix false positive in `must_use_candidate` [#4794](https://github.com/rust-lang/rust-clippy/pull/4794)
 +* Fix false positive in `print_with_newline` and `write_with_newline`
 +  [#4769](https://github.com/rust-lang/rust-clippy/pull/4769)
 +* Fix false positive in `derive_hash_xor_eq` [#4766](https://github.com/rust-lang/rust-clippy/pull/4766)
 +* Fix false positive in `missing_inline_in_public_items` [#4870](https://github.com/rust-lang/rust-clippy/pull/4870)
 +* Fix false positive in `string_add` [#4880](https://github.com/rust-lang/rust-clippy/pull/4880)
 +* Fix false positive in `float_arithmetic` [#4851](https://github.com/rust-lang/rust-clippy/pull/4851)
 +* Fix false positive in `cast_sign_loss` [#4883](https://github.com/rust-lang/rust-clippy/pull/4883)
 +* Fix false positive in `manual_swap` [#4877](https://github.com/rust-lang/rust-clippy/pull/4877)
 +* Fix ICEs occurring while checking some block expressions [#4772](https://github.com/rust-lang/rust-clippy/pull/4772)
 +* Fix ICE in `use_self` [#4776](https://github.com/rust-lang/rust-clippy/pull/4776)
 +* Fix ICEs related to `const_generics` [#4780](https://github.com/rust-lang/rust-clippy/pull/4780)
 +* Display help when running `clippy-driver` without arguments, instead of ICEing
 +  [#4810](https://github.com/rust-lang/rust-clippy/pull/4810)
 +* Clippy has its own ICE message now [#4588](https://github.com/rust-lang/rust-clippy/pull/4588)
 +* Show deprecated lints in the documentation again [#4757](https://github.com/rust-lang/rust-clippy/pull/4757)
 +* Improve Documentation by adding positive examples to some lints
 +  [#4832](https://github.com/rust-lang/rust-clippy/pull/4832)
 +
 +## Rust 1.40
 +
 +Released 2019-12-19
 +
 +[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb)
 +
 +* New Lints:
 +  * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
 +  * [`needless_doctest_main`] [#4603](https://github.com/rust-lang/rust-clippy/pull/4603)
 +  * [`suspicious_unary_op_formatting`] [#4615](https://github.com/rust-lang/rust-clippy/pull/4615)
 +  * [`debug_assert_with_mut_call`] [#4680](https://github.com/rust-lang/rust-clippy/pull/4680)
 +  * [`unused_self`] [#4619](https://github.com/rust-lang/rust-clippy/pull/4619)
 +  * [`inefficient_to_string`] [#4683](https://github.com/rust-lang/rust-clippy/pull/4683)
 +  * [`must_use_unit`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`must_use_candidate`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`double_must_use`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`comparison_chain`] [#4569](https://github.com/rust-lang/rust-clippy/pull/4569)
 +  * [`unsound_collection_transmute`] [#4592](https://github.com/rust-lang/rust-clippy/pull/4592)
 +  * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +* Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736)
 +* Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613)
 +* Expand `integer_arithmetic` to also detect mutating arithmetic like `+=` [#4585](https://github.com/rust-lang/rust-clippy/pull/4585)
 +* Fix false positive in `nonminimal_bool` [#4568](https://github.com/rust-lang/rust-clippy/pull/4568)
 +* Fix false positive in `missing_safety_doc` [#4611](https://github.com/rust-lang/rust-clippy/pull/4611)
 +* Fix false positive in `cast_sign_loss` [#4614](https://github.com/rust-lang/rust-clippy/pull/4614)
 +* Fix false positive in `redundant_clone` [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Fix false positive in `try_err` [#4721](https://github.com/rust-lang/rust-clippy/pull/4721)
 +* Fix false positive in `toplevel_ref_arg` [#4570](https://github.com/rust-lang/rust-clippy/pull/4570)
 +* Fix false positive in `multiple_inherent_impl` [#4593](https://github.com/rust-lang/rust-clippy/pull/4593)
 +* Improve more suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4575](https://github.com/rust-lang/rust-clippy/pull/4575)
 +* Improve suggestion for `zero_ptr` [#4599](https://github.com/rust-lang/rust-clippy/pull/4599)
 +* Improve suggestion for `explicit_counter_loop` [#4691](https://github.com/rust-lang/rust-clippy/pull/4691)
 +* Improve suggestion for `mul_add` [#4602](https://github.com/rust-lang/rust-clippy/pull/4602)
 +* Improve suggestion for `assertions_on_constants` [#4635](https://github.com/rust-lang/rust-clippy/pull/4635)
 +* Fix ICE in `use_self` [#4671](https://github.com/rust-lang/rust-clippy/pull/4671)
 +* Fix ICE when encountering const casts [#4590](https://github.com/rust-lang/rust-clippy/pull/4590)
 +
 +## Rust 1.39
 +
 +Released 2019-11-07
 +
 +[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b)
 +
 +* New Lints:
 +  * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
 +  * [`flat_map_identity`] [#4231](https://github.com/rust-lang/rust-clippy/pull/4231)
 +  * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535)
 +  * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511)
 +  * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394)
 +  * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386)
 +  * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498)
 +* Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348)
 +* Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403)
 +* Move `cast_lossless` to pedantic group [#4539](https://github.com/rust-lang/rust-clippy/pull/4539)
 +* `temporary_cstring_as_ptr` now catches more cases [#4425](https://github.com/rust-lang/rust-clippy/pull/4425)
 +* `use_self` now works in constructors, too [#4525](https://github.com/rust-lang/rust-clippy/pull/4525)
 +* `cargo_common_metadata` now checks for license files [#4518](https://github.com/rust-lang/rust-clippy/pull/4518)
 +* `cognitive_complexity` now includes the measured complexity in the warning message [#4469](https://github.com/rust-lang/rust-clippy/pull/4469)
 +* Fix false positives in `block_in_if_*` lints [#4458](https://github.com/rust-lang/rust-clippy/pull/4458)
 +* Fix false positive in `cast_lossless` [#4473](https://github.com/rust-lang/rust-clippy/pull/4473)
 +* Fix false positive in `clone_on_copy` [#4411](https://github.com/rust-lang/rust-clippy/pull/4411)
 +* Fix false positive in `deref_addrof` [#4487](https://github.com/rust-lang/rust-clippy/pull/4487)
 +* Fix false positive in `too_many_lines` [#4490](https://github.com/rust-lang/rust-clippy/pull/4490)
 +* Fix false positive in `new_ret_no_self` [#4365](https://github.com/rust-lang/rust-clippy/pull/4365)
 +* Fix false positive in `manual_swap` [#4478](https://github.com/rust-lang/rust-clippy/pull/4478)
 +* Fix false positive in `missing_const_for_fn` [#4450](https://github.com/rust-lang/rust-clippy/pull/4450)
 +* Fix false positive in `extra_unused_lifetimes` [#4477](https://github.com/rust-lang/rust-clippy/pull/4477)
 +* Fix false positive in `inherent_to_string` [#4460](https://github.com/rust-lang/rust-clippy/pull/4460)
 +* Fix false positive in `map_entry` [#4495](https://github.com/rust-lang/rust-clippy/pull/4495)
 +* Fix false positive in `unused_unit` [#4445](https://github.com/rust-lang/rust-clippy/pull/4445)
 +* Fix false positive in `redundant_pattern` [#4489](https://github.com/rust-lang/rust-clippy/pull/4489)
 +* Fix false positive in `wrong_self_convention` [#4369](https://github.com/rust-lang/rust-clippy/pull/4369)
 +* Improve various suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4558](https://github.com/rust-lang/rust-clippy/pull/4558)
 +* Improve suggestions for `redundant_pattern_matching` [#4352](https://github.com/rust-lang/rust-clippy/pull/4352)
 +* Improve suggestions for `explicit_write` [#4544](https://github.com/rust-lang/rust-clippy/pull/4544)
 +* Improve suggestion for `or_fun_call` [#4522](https://github.com/rust-lang/rust-clippy/pull/4522)
 +* Improve suggestion for `match_as_ref` [#4446](https://github.com/rust-lang/rust-clippy/pull/4446)
 +* Improve suggestion for `unnecessary_fold_span` [#4382](https://github.com/rust-lang/rust-clippy/pull/4382)
 +* Add suggestions for `unseparated_literal_suffix` [#4401](https://github.com/rust-lang/rust-clippy/pull/4401)
 +* Add suggestions for `char_lit_as_u8` [#4418](https://github.com/rust-lang/rust-clippy/pull/4418)
 +
 +## Rust 1.38
 +
 +Released 2019-09-26
 +
 +[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860)
 +
 +* New Lints:
 +  * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
 +  * [`inherent_to_string`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`inherent_to_string_shadow_display`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`type_repetition_in_bounds`] [#3766](https://github.com/rust-lang/rust-clippy/pull/3766)
 +  * [`try_err`] [#4222](https://github.com/rust-lang/rust-clippy/pull/4222)
 +* Move `{unnnecessary,panicking}_unwrap` out of nursery [#4307](https://github.com/rust-lang/rust-clippy/pull/4307)
 +* Extend the `use_self` lint to suggest uses of `Self::Variant` [#4308](https://github.com/rust-lang/rust-clippy/pull/4308)
 +* Improve suggestion for needless return [#4262](https://github.com/rust-lang/rust-clippy/pull/4262)
 +* Add auto-fixable suggestion for `let_unit` [#4337](https://github.com/rust-lang/rust-clippy/pull/4337)
 +* Fix false positive in `pub_enum_variant_names` and `enum_variant_names` [#4345](https://github.com/rust-lang/rust-clippy/pull/4345)
 +* Fix false positive in `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Fix false positive in `string_lit_as_bytes` [#4233](https://github.com/rust-lang/rust-clippy/pull/4233)
 +* Fix false positive in `needless_lifetimes` [#4266](https://github.com/rust-lang/rust-clippy/pull/4266)
 +* Fix false positive in `float_cmp` [#4275](https://github.com/rust-lang/rust-clippy/pull/4275)
 +* Fix false positives in `needless_return` [#4274](https://github.com/rust-lang/rust-clippy/pull/4274)
 +* Fix false negative in `match_same_arms` [#4246](https://github.com/rust-lang/rust-clippy/pull/4246)
 +* Fix incorrect suggestion for `needless_bool` [#4335](https://github.com/rust-lang/rust-clippy/pull/4335)
 +* Improve suggestion for `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Improve suggestion for `single_char_literal` [#4361](https://github.com/rust-lang/rust-clippy/pull/4361)
 +* Improve suggestion for `len_zero` [#4314](https://github.com/rust-lang/rust-clippy/pull/4314)
 +* Fix ICE in `implicit_hasher` [#4268](https://github.com/rust-lang/rust-clippy/pull/4268)
 +* Fix allow bug in `trivially_copy_pass_by_ref` [#4250](https://github.com/rust-lang/rust-clippy/pull/4250)
 +
 +## Rust 1.37
 +
 +Released 2019-08-15
 +
 +[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e)
 +
 +* New Lints:
 +  * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
 +  * [`get_last_with_len`] [#3832](https://github.com/rust-lang/rust-clippy/pull/3832)
 +  * [`integer_division`] [#4195](https://github.com/rust-lang/rust-clippy/pull/4195)
 +* Renamed Lint: `const_static_lifetime` is now called [`redundant_static_lifetimes`].
 +  The lint now covers statics in addition to consts [#4162](https://github.com/rust-lang/rust-clippy/pull/4162)
 +* [`match_same_arms`] now warns for all identical arms, instead of only the first one [#4102](https://github.com/rust-lang/rust-clippy/pull/4102)
 +* [`needless_return`] now works with void functions [#4220](https://github.com/rust-lang/rust-clippy/pull/4220)
 +* Fix false positive in [`redundant_closure`] [#4190](https://github.com/rust-lang/rust-clippy/pull/4190)
 +* Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107)
 +* Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214)
 +* Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136)
 +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164)
 +* Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119)
 +* Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137)
 +* Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071)
 +* Add macro check for [`unreadable_literal`] [#4099](https://github.com/rust-lang/rust-clippy/pull/4099)
 +
 +## Rust 1.36
 +
 +Released 2019-07-04
 +
 +[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7)
 +
 +* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
 +* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
 +* Move `path_buf_push_overwrite` to the nursery [#4013](https://github.com/rust-lang/rust-clippy/pull/4013)
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Allow allowing of [`toplevel_ref_arg`] lint [#4007](https://github.com/rust-lang/rust-clippy/pull/4007)
 +* Fix false negative in [`or_fun_call`] pertaining to nested constructors [#4084](https://github.com/rust-lang/rust-clippy/pull/4084)
 +* Fix false positive in [`or_fun_call`] pertaining to enum variant constructors [#4018](https://github.com/rust-lang/rust-clippy/pull/4018)
 +* Fix false positive in [`useless_let_if_seq`] pertaining to interior mutability [#4035](https://github.com/rust-lang/rust-clippy/pull/4035)
 +* Fix false positive in [`redundant_closure`] pertaining to non-function types [#4008](https://github.com/rust-lang/rust-clippy/pull/4008)
 +* Fix false positive in [`let_and_return`] pertaining to attributes on `let`s [#4024](https://github.com/rust-lang/rust-clippy/pull/4024)
 +* Fix false positive in [`module_name_repetitions`] lint pertaining to attributes [#4006](https://github.com/rust-lang/rust-clippy/pull/4006)
 +* Fix false positive on [`assertions_on_constants`] pertaining to `debug_assert!` [#3989](https://github.com/rust-lang/rust-clippy/pull/3989)
 +* Improve suggestion in [`map_clone`] to suggest `.copied()` where applicable  [#3970](https://github.com/rust-lang/rust-clippy/pull/3970) [#4043](https://github.com/rust-lang/rust-clippy/pull/4043)
 +* Improve suggestion for [`search_is_some`] [#4049](https://github.com/rust-lang/rust-clippy/pull/4049)
 +* Improve suggestion applicability for [`naive_bytecount`] [#3984](https://github.com/rust-lang/rust-clippy/pull/3984)
 +* Improve suggestion applicability for [`while_let_loop`] [#3975](https://github.com/rust-lang/rust-clippy/pull/3975)
 +* Improve diagnostics for [`too_many_arguments`] [#4053](https://github.com/rust-lang/rust-clippy/pull/4053)
 +* Improve diagnostics for [`cast_lossless`] [#4021](https://github.com/rust-lang/rust-clippy/pull/4021)
 +* Deal with macro checks in desugarings better [#4082](https://github.com/rust-lang/rust-clippy/pull/4082)
 +* Add macro check for [`unnecessary_cast`]  [#4026](https://github.com/rust-lang/rust-clippy/pull/4026)
 +* Remove [`approx_constant`]'s documentation's "Known problems" section. [#4027](https://github.com/rust-lang/rust-clippy/pull/4027)
 +* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 +* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 +
 +
 +## Rust 1.35
 +
 +Released 2019-05-20
 +
 +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
 +
 +* New lint: `drop_bounds` to detect `T: Drop` bounds
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
 +* Move [`get_unwrap`] to the restriction category
 +* Improve suggestions for [`iter_cloned_collect`]
 +* Improve suggestions for [`cast_lossless`] to suggest suffixed literals
 +* Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
 +* Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
 +* Fix false positive in [`bool_comparison`] pertaining to non-bool types
 +* Fix false positive in [`redundant_closure`] pertaining to differences in borrows
 +* Fix false positive in `option_map_unwrap_or` on non-copy types
 +* Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
 +* Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
 +* Fix false positive in [`needless_continue`] pertaining to loop labels
 +* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 +* Fix false positive for [`use_self`] in nested functions
 +* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
 +* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 +* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 +* Avoid triggering [`redundant_closure`] in macros
 +* ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
 +
 +## Rust 1.34
 +
 +Released 2019-04-10
 +
 +[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
 +
 +* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
 +* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
 +* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
 +* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
 +  configured using the `too-many-lines-threshold` configuration.
 +* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
 +* Expand `redundant_closure` to also work for methods (not only functions)
 +* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
 +* Fix false positive in `cast_sign_loss`
 +* Fix false positive in `integer_arithmetic`
 +* Fix false positive in `unit_arg`
 +* Fix false positives in `implicit_return`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `cast_lossless`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `needless_bool`
 +* Fix incorrect suggestion for `needless_range_loop`
 +* Fix incorrect suggestion for `use_self`
 +* Fix incorrect suggestion for `while_let_on_iterator`
 +* Clippy is now slightly easier to invoke in non-cargo contexts. See
 +  [#3665][pull3665] for more details.
 +* We now have [improved documentation][adding_lints] on how to add new lints
 +
 +## Rust 1.33
 +
 +Released 2019-02-26
 +
 +[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
 +
 +* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
 +* The `rust-clippy` repository is now part of the `rust-lang` org.
 +* Rename `stutter` to `module_name_repetitions`
 +* Merge `new_without_default_derive` into `new_without_default` lint
 +* Move `large_digit_groups` from `style` group to `pedantic`
 +* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
 +  comparisons against booleans
 +* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
 +* Expand `redundant_clone` to work on struct fields
 +* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
 +* Expand `use_self` to work on tuple structs and also in local macros
 +* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
 +* Fix false positives in `implicit_return`
 +* Fix false positives in `use_self`
 +* Fix false negative in `clone_on_copy`
 +* Fix false positive in `doc_markdown`
 +* Fix false positive in `empty_loop`
 +* Fix false positive in `if_same_then_else`
 +* Fix false positive in `infinite_iter`
 +* Fix false positive in `question_mark`
 +* Fix false positive in `useless_asref`
 +* Fix false positive in `wildcard_dependencies`
 +* Fix false positive in `write_with_newline`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `get_unwrap`
 +
 +## Rust 1.32
 +
 +Released 2019-01-17
 +
 +[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 +
 +* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`,
 +  [`redundant_clone`], [`wildcard_dependencies`],
 +  [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`],
 +  [`cargo_common_metadata`]
 +* Add support for `u128` and `i128` to integer related lints
 +* Add float support to `mistyped_literal_suffixes`
 +* Fix false positives in `use_self`
 +* Fix false positives in `missing_comma`
 +* Fix false positives in `new_ret_no_self`
 +* Fix false positives in `possible_missing_comma`
 +* Fix false positive in `integer_arithmetic` in constant items
 +* Fix false positive in `needless_borrow`
 +* Fix false positive in `out_of_bounds_indexing`
 +* Fix false positive in `new_without_default_derive`
 +* Fix false positive in `string_lit_as_bytes`
 +* Fix false negative in `out_of_bounds_indexing`
 +* Fix false negative in `use_self`. It will now also check existential types
 +* Fix incorrect suggestion for `redundant_closure_call`
 +* Fix various suggestions that contained expanded macros
 +* Fix `bool_comparison` triggering 3 times on on on the same code
 +* Expand `trivially_copy_pass_by_ref` to work on trait methods
 +* Improve suggestion for `needless_range_loop`
 +* Move `needless_pass_by_value` from `pedantic` group to `style`
 +
 +## Rust 1.31
 +
 +Released 2018-12-06
 +
 +[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
 +
 +* Clippy has been relicensed under a dual MIT / Apache license.
 +  See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
 +  information.
 +* With Rust 1.31, Clippy is no longer available via crates.io. The recommended
 +  installation method is via `rustup component add clippy`.
 +* New lints: [`redundant_pattern_matching`], [`unnecessary_filter_map`],
 +  [`unused_unit`], [`map_flatten`], [`mem_replace_option_with_none`]
 +* Fix ICE in `if_let_redundant_pattern_matching`
 +* Fix ICE in `needless_pass_by_value` when encountering a generic function
 +  argument with a lifetime parameter
 +* Fix ICE in `needless_range_loop`
 +* Fix ICE in `single_char_pattern` when encountering a constant value
 +* Fix false positive in `assign_op_pattern`
 +* Fix false positive in `boxed_local` on trait implementations
 +* Fix false positive in `cmp_owned`
 +* Fix false positive in `collapsible_if` when conditionals have comments
 +* Fix false positive in `double_parens`
 +* Fix false positive in `excessive_precision`
 +* Fix false positive in `explicit_counter_loop`
 +* Fix false positive in `fn_to_numeric_cast_with_truncation`
 +* Fix false positive in `map_clone`
 +* Fix false positive in `new_ret_no_self`
 +* Fix false positive in `new_without_default` when `new` is unsafe
 +* Fix false positive in `type_complexity` when using extern types
 +* Fix false positive in `useless_format`
 +* Fix false positive in `wrong_self_convention`
 +* Fix incorrect suggestion for `excessive_precision`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `get_unwrap`
 +* Fix incorrect suggestion for `useless_format`
 +* `fn_to_numeric_cast_with_truncation` lint can be disabled again
 +* Improve suggestions for `manual_memcpy`
 +* Improve help message for `needless_lifetimes`
 +
 +## Rust 1.30
 +
 +Released 2018-10-25
 +
 +[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad)
 +
 +* Deprecate `assign_ops` lint
 +* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
 +  [`needless_collect`], [`copy_iterator`]
 +* `cargo clippy -V` now includes the Clippy commit hash of the Rust
 +  Clippy component
 +* Fix ICE in `implicit_hasher`
 +* Fix ICE when encountering `println!("{}" a);`
 +* Fix ICE when encountering a macro call in match statements
 +* Fix false positive in `default_trait_access`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `similar_names`
 +* Fix false positive in `redundant_field_name`
 +* Fix false positive in `expect_fun_call`
 +* Fix false negative in `identity_conversion`
 +* Fix false negative in `explicit_counter_loop`
 +* Fix `range_plus_one` suggestion and false negative
 +* `print_with_newline` / `write_with_newline`: don't warn about string with several `\n`s in them
 +* Fix `useless_attribute` to also whitelist `unused_extern_crates`
 +* Fix incorrect suggestion for `single_char_pattern`
 +* Improve suggestion for `identity_conversion` lint
 +* Move `explicit_iter_loop` and `explicit_into_iter_loop` from `style` group to `pedantic`
 +* Move `range_plus_one` and `range_minus_one` from `nursery` group to `complexity`
 +* Move `shadow_unrelated` from `restriction` group to `pedantic`
 +* Move `indexing_slicing` from `pedantic` group to `restriction`
 +
 +## Rust 1.29
 +
 +Released 2018-09-13
 +
 +[v0.0.212...14207503](https://github.com/rust-lang/rust-clippy/compare/v0.0.212...14207503)
 +
 +* :tada: :tada: **Rust 1.29 is the first stable Rust that includes a bundled Clippy** :tada:
 +  :tada:
 +  You can now run `rustup component add clippy-preview` and then `cargo
 +  clippy` to run Clippy. This should put an end to the continuous nightly
 +  upgrades for Clippy users.
 +* Clippy now follows the Rust versioning scheme instead of its own
 +* Fix ICE when encountering a `while let (..) = x.iter()` construct
 +* Fix false positives in `use_self`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `useless_attribute` lint
 +* Fix false positive in `print_literal`
 +* Fix `use_self` regressions
 +* Improve lint message for `neg_cmp_op_on_partial_ord`
 +* Improve suggestion highlight for `single_char_pattern`
 +* Improve suggestions for various print/write macro lints
 +* Improve website header
 +
 +## 0.0.212 (2018-07-10)
 +* Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 +
 +## 0.0.211
 +* Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
 +
 +## 0.0.210
 +* Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
 +
 +## 0.0.209
 +* Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
 +
 +## 0.0.208
 +* Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
 +
 +## 0.0.207
 +* Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
 +
 +## 0.0.206
 +* Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
 +
 +## 0.0.205
 +* Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
 +* Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
 +
 +## 0.0.204
 +* Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
 +
 +## 0.0.203
 +* Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
 +* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 +
 +## 0.0.202
 +* Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
 +
 +## 0.0.201
 +* Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
 +
 +## 0.0.200
 +* Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
 +
 +## 0.0.199
 +* Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
 +
 +## 0.0.198
 +* Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
 +
 +## 0.0.197
 +* Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
 +
 +## 0.0.196
 +* Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
 +
 +## 0.0.195
 +* Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
 +
 +## 0.0.194
 +* Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
 +* New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
 +
 +## 0.0.193
 +* Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
 +
 +## 0.0.192
 +* Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
 +* New lint: [`print_literal`]
 +
 +## 0.0.191
 +* Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
 +* Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
 +
 +## 0.0.190
 +* Fix a bunch of intermittent cargo bugs
 +
 +## 0.0.189
 +* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
 +
 +## 0.0.188
 +* Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
 +* New lint: [`while_immutable_condition`]
 +
 +## 0.0.187
 +* Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
 +* New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
 +
 +## 0.0.186
 +* Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
 +* Various false positive fixes
 +
 +## 0.0.185
 +* Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
 +* New lint: [`question_mark`]
 +
 +## 0.0.184
 +* Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
 +* New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
 +
 +## 0.0.183
 +* Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
 +* New lint: [`misaligned_transmute`]
 +
 +## 0.0.182
 +* Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
 +* New lint: [`decimal_literal_representation`]
 +
 +## 0.0.181
 +* Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
 +* New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
 +* Removed `unit_expr`
 +* Various false positive fixes for [`needless_pass_by_value`]
 +
 +## 0.0.180
 +* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
 +
 +## 0.0.179
 +* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
 +
 +## 0.0.178
 +* Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
 +
 +## 0.0.177
 +* Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
 +* New lint: [`match_as_ref`]
 +
 +## 0.0.176
 +* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
 +
 +## 0.0.175
 +* Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
 +
 +## 0.0.174
 +* Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
 +
 +## 0.0.173
 +* Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
 +
 +## 0.0.172
 +* Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
 +
 +## 0.0.171
 +* Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
 +
 +## 0.0.170
 +* Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
 +
 +## 0.0.169
 +* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
 +* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
 +
 +## 0.0.168
 +* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
 +
 +## 0.0.167
 +* Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
 +* New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
 +
 +## 0.0.166
 +* Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
 +* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], `invalid_ref`, [`option_map_or_none`],
 +  [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
 +  [`transmute_int_to_float`]
 +
 +## 0.0.165
 +* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
 +* New lint: [`mut_range_bound`]
 +
 +## 0.0.164
 +* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
 +* New lint: [`int_plus_one`]
 +
 +## 0.0.163
 +* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
 +
 +## 0.0.162
 +* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
 +* New lint: [`chars_last_cmp`]
 +* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
 +
 +## 0.0.161
 +* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
 +
 +## 0.0.160
 +* Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
 +
 +## 0.0.159
 +* Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
 +* New lint: [`clone_on_ref_ptr`]
 +
 +## 0.0.158
 +* New lint: [`manual_memcpy`]
 +* [`cast_lossless`] no longer has redundant parentheses in its suggestions
 +* Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
 +
 +## 0.0.157 - 2017-09-04
 +* Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
 +* New lint: `unit_expr`
 +
 +## 0.0.156 - 2017-09-03
 +* Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
 +
 +## 0.0.155
 +* Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
 +* New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
 +
 +## 0.0.154
 +* Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
 +* Fix [`use_self`] triggering inside derives
 +* Add support for linting an entire workspace with `cargo clippy --all`
 +* New lint: [`naive_bytecount`]
 +
 +## 0.0.153
 +* Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
 +* New lint: [`use_self`]
 +
 +## 0.0.152
 +* Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
 +
 +## 0.0.151
 +* Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
 +
 +## 0.0.150
 +* Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
 +
 +## 0.0.148
 +* Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
 +* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
 +
 +## 0.0.147
 +* Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
 +
 +## 0.0.146
 +* Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
 +* Fixes false positives in `inline_always`
 +* Fixes false negatives in `panic_params`
 +
 +## 0.0.145
 +* Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
 +
 +## 0.0.144
 +* Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
 +
 +## 0.0.143
 +* Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
 +* Fix `cargo clippy` crashing on `dylib` projects
 +* Fix false positives around `nested_while_let` and `never_loop`
 +
 +## 0.0.142
 +* Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
 +
 +## 0.0.141
 +* Rewrite of the `doc_markdown` lint.
 +* Deprecated [`range_step_by_zero`]
 +* New lint: [`iterator_step_by_zero`]
 +* New lint: [`needless_borrowed_reference`]
 +* Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
 +
 +## 0.0.140 - 2017-06-16
 +* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
 +
 +## 0.0.139 — 2017-06-10
 +* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
 +* Fix bugs with for loop desugaring
 +* Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
 +
 +## 0.0.138 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
 +
 +## 0.0.137 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
 +
 +## 0.0.136 — 2017—05—26
 +* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
 +
 +## 0.0.135 — 2017—05—24
 +* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
 +
 +## 0.0.134 — 2017—05—19
 +* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
 +
 +## 0.0.133 — 2017—05—14
 +* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
 +
 +## 0.0.132 — 2017—05—05
 +* Fix various bugs and some ices
 +
 +## 0.0.131 — 2017—05—04
 +* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
 +
 +## 0.0.130 — 2017—05—03
 +* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
 +
 +## 0.0.129 — 2017-05-01
 +* Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
 +
 +## 0.0.128 — 2017-04-28
 +* Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
 +
 +## 0.0.127 — 2017-04-27
 +* Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
 +* New lint: [`needless_continue`]
 +
 +## 0.0.126 — 2017-04-24
 +* Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
 +
 +## 0.0.125 — 2017-04-19
 +* Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
 +
 +## 0.0.124 — 2017-04-16
 +* Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
 +
 +## 0.0.123 — 2017-04-07
 +* Fix various false positives
 +
 +## 0.0.122 — 2017-04-07
 +* Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
 +* New lint: [`op_ref`]
 +
 +## 0.0.121 — 2017-03-21
 +* Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
 +
 +## 0.0.120 — 2017-03-17
 +* Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
 +
 +## 0.0.119 — 2017-03-13
 +* Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
 +
 +## 0.0.118 — 2017-03-05
 +* Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
 +
 +## 0.0.117 — 2017-03-01
 +* Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
 +
 +## 0.0.116 — 2017-02-28
 +* Fix `cargo clippy` on 64 bit windows systems
 +
 +## 0.0.115 — 2017-02-27
 +* Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
 +* New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
 +
 +## 0.0.114 — 2017-02-08
 +* Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
 +* Tests are now ui tests (testing the exact output of rustc)
 +
 +## 0.0.113 — 2017-02-04
 +* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
 +* New lint: [`large_enum_variant`]
 +* `explicit_into_iter_loop` provides suggestions
 +
 +## 0.0.112 — 2017-01-27
 +* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
 +
 +## 0.0.111 — 2017-01-21
 +* Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
 +
 +## 0.0.110 — 2017-01-20
 +* Add badges and categories to `Cargo.toml`
 +
 +## 0.0.109 — 2017-01-19
 +* Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
 +
 +## 0.0.108 — 2017-01-12
 +* Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
 +
 +## 0.0.107 — 2017-01-11
 +* Update regex dependency
 +* Fix FP when matching `&&mut` by `&ref`
 +* Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
 +* New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
 +
 +## 0.0.106 — 2017-01-04
 +* Fix FP introduced by rustup in [`wrong_self_convention`]
 +
 +## 0.0.105 — 2017-01-04
 +* Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
 +* New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
 +* Fix suggestion in [`new_without_default`]
 +* FP fix in [`absurd_extreme_comparisons`]
 +
 +## 0.0.104 — 2016-12-15
 +* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
 +
 +## 0.0.103 — 2016-11-25
 +* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
 +
 +## 0.0.102 — 2016-11-24
 +* Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
 +
 +## 0.0.101 — 2016-11-23
 +* Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
 +* New lint: [`string_extend_chars`]
 +
 +## 0.0.100 — 2016-11-20
 +* Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
 +
 +## 0.0.99 — 2016-11-18
 +* Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
 +* New lint: [`get_unwrap`]
 +
 +## 0.0.98 — 2016-11-08
 +* Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
 +
 +## 0.0.97 — 2016-11-03
 +* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
 +  previously added for a short time under the name `clippy` but removed for
 +  compatibility.
 +* `cargo clippy --help` is more helping (and less helpful :smile:)
 +* Rustup to *rustc 1.14.0-nightly (5665bdf3e 2016-11-02)*
 +* New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
 +
 +## 0.0.96 — 2016-10-22
 +* Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
 +* New lint: [`iter_skip_next`]
 +
 +## 0.0.95 — 2016-10-06
 +* Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
 +
 +## 0.0.94 — 2016-10-04
 +* Fixes bustage on Windows due to forbidden directory name
 +
 +## 0.0.93 — 2016-10-03
 +* Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
 +* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
 +  allowed by default.
 +* New lint: [`explicit_into_iter_loop`]
 +
 +## 0.0.92 — 2016-09-30
 +* Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
 +
 +## 0.0.91 — 2016-09-28
 +* Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
 +
 +## 0.0.90 — 2016-09-09
 +* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
 +
 +## 0.0.89 — 2016-09-06
 +* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
 +
 +## 0.0.88 — 2016-09-04
 +* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
 +* The following lints are not new but were only usable through the `clippy`
 +  lint groups: [`filter_next`], `for_loop_over_option`,
 +  `for_loop_over_result` and [`match_overlapping_arm`]. You should now be
 +  able to `#[allow/deny]` them individually and they are available directly
 +  through `cargo clippy`.
 +
 +## 0.0.87 — 2016-08-31
 +* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
 +* New lints: [`builtin_type_shadow`]
 +* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
 +
 +## 0.0.86 — 2016-08-28
 +* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
 +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
 +
 +## 0.0.85 — 2016-08-19
 +* Fix ICE with [`useless_attribute`]
 +* [`useless_attribute`] ignores `unused_imports` on `use` statements
 +
 +## 0.0.84 — 2016-08-18
 +* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
 +
 +## 0.0.83 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
 +* New lints: [`print_with_newline`], [`useless_attribute`]
 +
 +## 0.0.82 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
 +* New lint: [`module_inception`]
 +
 +## 0.0.81 — 2016-08-14
 +* Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
 +* New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
 +* False positive fix in [`too_many_arguments`]
 +* Addition of functionality to [`needless_borrow`]
 +* Suggestions for [`clone_on_copy`]
 +* Bug fix in [`wrong_self_convention`]
 +* Doc improvements
 +
 +## 0.0.80 — 2016-07-31
 +* Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
 +* New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
 +
 +## 0.0.79 — 2016-07-10
 +* Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
 +* Major suggestions refactoring
 +
 +## 0.0.78 — 2016-07-02
 +* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
 +* New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
 +* For compatibility, `cargo clippy` does not defines the `clippy` feature
 +  introduced in 0.0.76 anymore
 +* [`collapsible_if`] now considers `if let`
 +
 +## 0.0.77 — 2016-06-21
 +* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
 +* New lints: `stutter` and [`iter_nth`]
 +
 +## 0.0.76 — 2016-06-10
 +* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
 +* `cargo clippy` now automatically defines the `clippy` feature
 +* New lint: [`not_unsafe_ptr_arg_deref`]
 +
 +## 0.0.75 — 2016-06-08
 +* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
 +
 +## 0.0.74 — 2016-06-07
 +* Fix bug with `cargo-clippy` JSON parsing
 +* Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
 +  “for further information visit *lint-link*” message.
 +
 +## 0.0.73 — 2016-06-05
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.72 — 2016-06-04
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.71 — 2016-05-31
 +* Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
 +* New lint: [`useless_let_if_seq`]
 +
 +## 0.0.70 — 2016-05-28
 +* Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
 +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
 +  `RegexBuilder::new` and byte regexes
 +
 +## 0.0.69 — 2016-05-20
 +* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
 +* [`used_underscore_binding`] has been made `Allow` temporarily
 +
 +## 0.0.68 — 2016-05-17
 +* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
 +* New lint: [`unnecessary_operation`]
 +
 +## 0.0.67 — 2016-05-12
 +* Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
 +
 +## 0.0.66 — 2016-05-11
 +* New `cargo clippy` subcommand
 +* New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
 +
 +## 0.0.65 — 2016-05-08
 +* Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
 +* New lints: [`float_arithmetic`], [`integer_arithmetic`]
 +
 +## 0.0.64 — 2016-04-26
 +* Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
 +* New lints: `temporary_cstring_as_ptr`, [`unsafe_removed_from_name`], and [`mem_forget`]
 +
 +## 0.0.63 — 2016-04-08
 +* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
 +
 +## 0.0.62 — 2016-04-07
 +* Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
 +
 +## 0.0.61 — 2016-04-03
 +* Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
 +* New lint: [`invalid_upcast_comparisons`]
 +
 +## 0.0.60 — 2016-04-01
 +* Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
 +
 +## 0.0.59 — 2016-03-31
 +* Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
 +* New lints: [`logic_bug`], [`nonminimal_bool`]
 +* Fixed: [`match_same_arms`] now ignores arms with guards
 +* Improved: [`useless_vec`] now warns on `for … in vec![…]`
 +
 +## 0.0.58 — 2016-03-27
 +* Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
 +* New lint: [`doc_markdown`]
 +
 +## 0.0.57 — 2016-03-27
 +* Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
 +* Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
 +* New lint: [`crosspointer_transmute`]
 +
 +## 0.0.56 — 2016-03-23
 +* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
 +* New lints: [`many_single_char_names`] and [`similar_names`]
 +
 +## 0.0.55 — 2016-03-21
 +* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
 +
 +## 0.0.54 — 2016-03-16
 +* Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
 +
 +## 0.0.53 — 2016-03-15
 +* Add a [configuration file]
 +
 +## ~~0.0.52~~
 +
 +## 0.0.51 — 2016-03-13
 +* Add `str` to types considered by [`len_zero`]
 +* New lints: [`indexing_slicing`]
 +
 +## 0.0.50 — 2016-03-11
 +* Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
 +
 +## 0.0.49 — 2016-03-09
 +* Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
 +* New lints: [`overflow_check_conditional`], `unused_label`, [`new_without_default`]
 +
 +## 0.0.48 — 2016-03-07
 +* Fixed: ICE in [`needless_range_loop`] with globals
 +
 +## 0.0.47 — 2016-03-07
 +* Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
 +* New lint: [`redundant_closure_call`]
 +
 +[`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html
 +[`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
 +[configuration file]: ./rust-clippy#configuration
 +[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
 +
 +<!-- lint disable no-unused-definitions -->
 +<!-- begin autogenerated links to lint list -->
 +[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 +[`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
 +[`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_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
 +[`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_abs_to_unsigned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned
 +[`cast_enum_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_constructor
 +[`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation
 +[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 +[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 +[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 +[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
 +[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 +[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 +[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
 +[`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
++[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
 +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 +[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 +[`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
 +[`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation
 +[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 +[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 +[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 +[`deref_by_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_by_slicing
 +[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
 +[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 +[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 +[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
 +[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 +[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 +[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 +[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 +[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 +[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 +[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
++[`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`duplicate_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
++[`empty_structs_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_structs_with_brackets
 +[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
 +[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
 +[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
 +[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
 +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 +[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
++[`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
 +[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 +[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
 +[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
 +[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
 +[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
 +[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
 +[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used
 +[`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
 +[`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop
 +[`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods
 +[`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
 +[`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
 +[`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write
 +[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 +[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
 +[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
 +[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 +[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 +[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 +[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 +[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 +[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
 +[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
 +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
 +[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
 +[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
 +[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
 +[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 +[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 +[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
 +[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 +[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
 +[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 +[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
++[`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
 +[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
 +[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 +[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 +[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 +[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 +[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 +[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 +[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 +[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 +[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
 +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 +[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 +[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
 +[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
 +[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
 +[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
 +[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
 +[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
 +[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
 +[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 +[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 +[`init_numbered_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#init_numbered_fields
 +[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
 +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
 +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 +[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 +[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 +[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
 +[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 +[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 +[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 +[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 +[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
 +[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 +[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
 +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
 +[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
 +[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
 +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 +[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
 +[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 +[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 +[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
 +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
 +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
 +[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 +[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 +[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 +[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
 +[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
 +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 +[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
 +[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 +[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 +[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 +[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 +[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 +[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 +[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 +[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 +[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
 +[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 +[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 +[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
 +[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 +[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 +[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 +[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 +[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 +[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
 +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
 +[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
 +[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
 +[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
 +[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
 +[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
 +[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
 +[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 +[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
 +[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 +[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 +[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 +[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 +[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 +[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 +[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 +[`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
 +[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
 +[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 +[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
 +[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 +[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 +[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
 +[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
 +[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 +[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
 +[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 +[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 +[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
 +[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
 +[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
 +[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
 +[`mut_mutex_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mutex_lock
 +[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
 +[`mutable_key_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
 +[`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
 +[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 +[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 +[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 +[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 +[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 +[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 +[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 +[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 +[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 +[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 +[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
 +[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match
 +[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 +[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 +[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 +[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 +[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 +[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
 +[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
 +[`negative_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#negative_feature_names
 +[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 +[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 +[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 +[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
 +[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
 +[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 +[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes
 +[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 +[`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`option_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
 +[`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
 +[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 +[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 +[`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_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
 +[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
 +[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
 +[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 +[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 +[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 +[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 +[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 +[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 +[`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
 +[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
 +[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 +[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
 +[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 +[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
 +[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 +[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 +[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 +[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 +[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 +[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 +[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 +[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 +[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 +[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 +[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 +[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 +[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
 +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 +[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
 +[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 +[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 +[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
 +[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 +[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 +[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 +[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 +[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
 +[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 +[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 +[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 +[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 +[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
 +[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 +[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 +[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 +[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 +[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 +[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 +[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 +[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
 +[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 +[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
 +[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 +[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
 +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 +[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 +[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
 +[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
 +[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 +[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 +[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 +[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 +[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
 +[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 +[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 +[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 +[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
 +[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
 +[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 +[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 +[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 +[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 +[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 +[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
 +[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 +[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 +[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 +[`transmute_undefined_repr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_undefined_repr
 +[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 +[`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 +[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
 +[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
 +[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 +[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 +[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
 +[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
 +[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 +[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 +[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
 +[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
 +[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
 +[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
 +[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
 +[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
 +[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join
 +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 +[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 +[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 +[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
 +[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
 +[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
 +[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
 +[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
 +[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
 +[`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize
 +[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
 +[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization
 +[`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
 +[`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 +[`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 +[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
 +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 +[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 +[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 +[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 +[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 +[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
 +[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 +[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
 +[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
 +[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
 +[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
 +[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 +[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
 +[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 +[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 +[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
 +[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 +[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 +[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
 +[`vec_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
 +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 +[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 +[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 +[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 +[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 +[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 +[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
 +[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
 +[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
 +[`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports
 +[`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns
 +[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
 +[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
 +[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string
 +[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
 +[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
 +[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
 +[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 +[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 +[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
 +[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index 123af23881b623ffd7ba83b8f1a259db3fa49b40,0000000000000000000000000000000000000000..dd6518d5241b5fad11f356ae2fa089f3218a109e
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,64 @@@
- version = "0.1.61"
 +[package]
 +name = "clippy"
- clippy_lints = { version = "0.1", path = "clippy_lints" }
++version = "0.1.62"
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +categories = ["development-tools", "development-tools::cargo-plugins"]
 +build = "build.rs"
 +edition = "2021"
 +publish = false
 +
 +[[bin]]
 +name = "cargo-clippy"
 +test = false
 +path = "src/main.rs"
 +
 +[[bin]]
 +name = "clippy-driver"
 +path = "src/driver.rs"
 +
 +[dependencies]
- rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
++clippy_lints = { path = "clippy_lints" }
 +semver = "1.0"
- cargo_metadata = "0.14"
++rustc_tools_util = { path = "rustc_tools_util" }
 +tempfile = { version = "3.2", optional = true }
 +
 +[dev-dependencies]
- serde = { version = "1.0", features = ["derive"] }
 +compiletest_rs = { version = "0.7.1", features = ["tmp"] }
 +tester = "0.9"
 +regex = "1.5"
 +# This is used by the `collect-metadata` alias.
 +filetime = "0.2"
 +
 +# A noop dependency that changes in the Rust repository, it's a bit of a hack.
 +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
 +# for more information.
 +rustc-workspace-hack = "1.0"
 +
 +# UI test dependencies
 +clippy_utils = { path = "clippy_utils" }
 +derive-new = "0.5"
 +if_chain = "1.0"
 +itertools = "0.10.1"
 +quote = "1.0"
++serde = { version = "1.0.125", features = ["derive"] }
 +syn = { version = "1.0", features = ["full"] }
 +futures = "0.3"
 +parking_lot = "0.11.2"
 +tokio = { version = "1", features = ["io-util"] }
 +rustc-semver = "1.1"
 +
 +[build-dependencies]
 +rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 +
 +[features]
 +deny-warnings = ["clippy_lints/deny-warnings"]
 +integration = ["tempfile"]
 +internal = ["clippy_lints/internal"]
 +
 +[package.metadata.rust-analyzer]
 +# This package uses #[feature(rustc_private)]
 +rustc_private = true
index d133e8cddabc729b96ec2d2617401a771883660a,0000000000000000000000000000000000000000..c2ebba0683ca9b85ef0dd6bcdb11f33a768f2e80
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,20 @@@
- bytecount = "0.6"
 +[package]
 +name = "clippy_dev"
 +version = "0.0.1"
 +edition = "2021"
 +
 +[dependencies]
- regex = "1.5"
 +clap = "2.33"
 +indoc = "1.0"
 +itertools = "0.10.1"
 +opener = "0.5"
- cargo_metadata = "0.14"
 +shell-escape = "0.1"
++tempfile = "3.3"
 +walkdir = "2.3"
 +
 +[features]
 +deny-warnings = []
++
++[package.metadata.rust-analyzer]
++# This package uses #[feature(rustc_private)]
++rustc_private = true
index b0fb39e8169968aa57624a6d988879a11021b02c,0000000000000000000000000000000000000000..8e5c739afe05ae85e3a00cee769678233806b5ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,60 @@@
- #[cfg(not(windows))]
- static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
- #[cfg(windows)]
- static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
- static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
-     let mut path = std::env::current_exe().unwrap();
-     path.set_file_name(CARGO_CLIPPY_EXE);
-     fs::metadata(path).ok()?.modified().ok()
- });
 +//! `bless` updates the reference files in the repo with changed output files
 +//! from the last test run.
 +
++use crate::cargo_clippy_path;
 +use std::ffi::OsStr;
 +use std::fs;
 +use std::lazy::SyncLazy;
 +use std::path::{Path, PathBuf};
 +use walkdir::{DirEntry, WalkDir};
 +
++static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> =
++    SyncLazy::new(|| cargo_clippy_path().metadata().ok()?.modified().ok());
 +
 +/// # Panics
 +///
 +/// Panics if the path to a test file is broken
 +pub fn bless(ignore_timestamp: bool) {
 +    let extensions = ["stdout", "stderr", "fixed"].map(OsStr::new);
 +
 +    WalkDir::new(build_dir())
 +        .into_iter()
 +        .map(Result::unwrap)
 +        .filter(|entry| entry.path().extension().map_or(false, |ext| extensions.contains(&ext)))
 +        .for_each(|entry| update_reference_file(&entry, ignore_timestamp));
 +}
 +
 +fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
 +    let test_output_path = test_output_entry.path();
 +
 +    let reference_file_name = test_output_entry.file_name().to_str().unwrap().replace(".stage-id", "");
 +    let reference_file_path = Path::new("tests")
 +        .join(test_output_path.strip_prefix(build_dir()).unwrap())
 +        .with_file_name(reference_file_name);
 +
 +    // If the test output was not updated since the last clippy build, it may be outdated
 +    if !ignore_timestamp && !updated_since_clippy_build(test_output_entry).unwrap_or(true) {
 +        return;
 +    }
 +
 +    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
 +    let reference_file = fs::read(&reference_file_path).unwrap_or_default();
 +
 +    if test_output_file != reference_file {
 +        // If a test run caused an output file to change, update the reference file
 +        println!("updating {}", reference_file_path.display());
 +        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
 +    }
 +}
 +
 +fn updated_since_clippy_build(entry: &DirEntry) -> Option<bool> {
 +    let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
 +    let modified = entry.metadata().ok()?.modified().ok()?;
 +    Some(modified >= clippy_build_time)
 +}
 +
 +fn build_dir() -> PathBuf {
 +    let mut path = std::env::current_exe().unwrap();
 +    path.set_file_name("test");
 +    path
 +}
index 59fde447547145f3093b5054112bd58dd6ec8b7e,0000000000000000000000000000000000000000..9c6d754b400fc0f41595cfd8a4a745a1de926dd9
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,56 @@@
++#![feature(let_else)]
 +#![feature(once_cell)]
++#![feature(rustc_private)]
 +#![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)]
 +
++extern crate rustc_lexer;
++
 +use std::path::PathBuf;
 +
 +pub mod bless;
 +pub mod fmt;
 +pub mod lint;
 +pub mod new_lint;
 +pub mod serve;
 +pub mod setup;
 +pub mod update_lints;
 +
++#[cfg(not(windows))]
++static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
++#[cfg(windows)]
++static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
++
++/// Returns the path to the `cargo-clippy` binary
++#[must_use]
++pub fn cargo_clippy_path() -> PathBuf {
++    let mut path = std::env::current_exe().expect("failed to get current executable name");
++    path.set_file_name(CARGO_CLIPPY_EXE);
++    path
++}
++
 +/// 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 b8287980a4bacea5df7cadbe2a50621eac7e6131,0000000000000000000000000000000000000000..1bc1a39542db5c00bb0ebc1dd854d4b90b5aa859
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,52 @@@
- use std::process::{self, Command};
++use crate::cargo_clippy_path;
++use std::process::{self, Command, ExitStatus};
++use std::{fs, io};
 +
- pub fn run(filename: &str) {
-     let code = Command::new("cargo")
-         .args(["run", "--bin", "clippy-driver", "--"])
-         .args(["-L", "./target/debug"])
-         .args(["-Z", "no-codegen"])
-         .args(["--edition", "2021"])
-         .arg(filename)
-         .status()
-         .expect("failed to run cargo")
-         .code();
-     if code.is_none() {
-         eprintln!("Killed by signal");
++fn exit_if_err(status: io::Result<ExitStatus>) {
++    match status.expect("failed to run command").code() {
++        Some(0) => {},
++        Some(n) => process::exit(n),
++        None => {
++            eprintln!("Killed by signal");
++            process::exit(1);
++        },
 +    }
++}
++
++pub fn run(path: &str) {
++    let is_file = match fs::metadata(path) {
++        Ok(metadata) => metadata.is_file(),
++        Err(e) => {
++            eprintln!("Failed to read {path}: {e:?}");
++            process::exit(1);
++        },
++    };
++
++    if is_file {
++        exit_if_err(
++            Command::new("cargo")
++                .args(["run", "--bin", "clippy-driver", "--"])
++                .args(["-L", "./target/debug"])
++                .args(["-Z", "no-codegen"])
++                .args(["--edition", "2021"])
++                .arg(path)
++                .status(),
++        );
++    } else {
++        exit_if_err(Command::new("cargo").arg("build").status());
 +
-     process::exit(code.unwrap_or(1));
++        // Run in a tempdir as changes to clippy do not retrigger linting
++        let target = tempfile::Builder::new()
++            .prefix("clippy")
++            .tempdir()
++            .expect("failed to create tempdir");
++
++        let status = Command::new(cargo_clippy_path())
++            .current_dir(path)
++            .env("CARGO_TARGET_DIR", target.as_ref())
++            .status();
++
++        target.close().expect("failed to remove tempdir");
++        exit_if_err(status);
++    }
 +}
index 30a241c8ba151e1cfa3b1385156f13ddd892eb06,0000000000000000000000000000000000000000..b1fe35a0243f04e4887cdb020edd0de32040c7eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,236 -1,0 +1,246 @@@
-             let filename = matches.value_of("filename").unwrap();
-             lint::run(filename);
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +
 +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
 +use clippy_dev::{bless, fmt, lint, new_lint, serve, setup, update_lints};
++use indoc::indoc;
 +fn main() {
 +    let matches = get_clap_config();
 +
 +    match matches.subcommand() {
 +        ("bless", Some(matches)) => {
 +            bless::bless(matches.is_present("ignore-timestamp"));
 +        },
 +        ("fmt", Some(matches)) => {
 +            fmt::run(matches.is_present("check"), matches.is_present("verbose"));
 +        },
 +        ("update_lints", Some(matches)) => {
 +            if matches.is_present("print-only") {
 +                update_lints::print_lints();
 +            } else if matches.is_present("check") {
 +                update_lints::run(update_lints::UpdateMode::Check);
 +            } else {
 +                update_lints::run(update_lints::UpdateMode::Change);
 +            }
 +        },
 +        ("new_lint", Some(matches)) => {
 +            match new_lint::create(
 +                matches.value_of("pass"),
 +                matches.value_of("name"),
 +                matches.value_of("category"),
 +                matches.is_present("msrv"),
 +            ) {
 +                Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
 +                Err(e) => eprintln!("Unable to create lint: {}", e),
 +            }
 +        },
 +        ("setup", Some(sub_command)) => match sub_command.subcommand() {
 +            ("intellij", Some(matches)) => setup::intellij::setup_rustc_src(
 +                matches
 +                    .value_of("rustc-repo-path")
 +                    .expect("this field is mandatory and therefore always valid"),
 +            ),
 +            ("git-hook", Some(matches)) => setup::git_hook::install_hook(matches.is_present("force-override")),
 +            ("vscode-tasks", Some(matches)) => setup::vscode::install_tasks(matches.is_present("force-override")),
 +            _ => {},
 +        },
 +        ("remove", Some(sub_command)) => match sub_command.subcommand() {
 +            ("git-hook", Some(_)) => setup::git_hook::remove_hook(),
 +            ("intellij", Some(_)) => setup::intellij::remove_rustc_src(),
 +            ("vscode-tasks", Some(_)) => setup::vscode::remove_tasks(),
 +            _ => {},
 +        },
 +        ("serve", Some(matches)) => {
 +            let port = matches.value_of("port").unwrap().parse().unwrap();
 +            let lint = matches.value_of("lint");
 +            serve::run(port, lint);
 +        },
 +        ("lint", Some(matches)) => {
-                 .about("Manually run clippy on a file")
++            let path = matches.value_of("path").unwrap();
++            lint::run(path);
 +        },
 +        _ => {},
 +    }
 +}
 +
 +fn get_clap_config<'a>() -> ArgMatches<'a> {
 +    App::new("Clippy developer tooling")
 +        .setting(AppSettings::ArgRequiredElseHelp)
 +        .subcommand(
 +            SubCommand::with_name("bless")
 +                .about("bless the test output changes")
 +                .arg(
 +                    Arg::with_name("ignore-timestamp")
 +                        .long("ignore-timestamp")
 +                        .help("Include files updated before clippy was built"),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("fmt")
 +                .about("Run rustfmt on all projects and tests")
 +                .arg(
 +                    Arg::with_name("check")
 +                        .long("check")
 +                        .help("Use the rustfmt --check option"),
 +                )
 +                .arg(
 +                    Arg::with_name("verbose")
 +                        .short("v")
 +                        .long("verbose")
 +                        .help("Echo commands run"),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("update_lints")
 +                .about("Updates lint registration and information from the source code")
 +                .long_about(
 +                    "Makes sure that:\n \
 +                 * the lint count in README.md is correct\n \
 +                 * the changelog contains markdown link references at the bottom\n \
 +                 * all lint groups include the correct lints\n \
 +                 * lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \
 +                 * all lints are registered in the lint store",
 +                )
 +                .arg(Arg::with_name("print-only").long("print-only").help(
 +                    "Print a table of lints to STDOUT. \
 +                 This does not include deprecated and internal lints. \
 +                 (Does not modify any files)",
 +                ))
 +                .arg(
 +                    Arg::with_name("check")
 +                        .long("check")
 +                        .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("new_lint")
 +                .about("Create new lint and run `cargo dev update_lints`")
 +                .arg(
 +                    Arg::with_name("pass")
 +                        .short("p")
 +                        .long("pass")
 +                        .help("Specify whether the lint runs during the early or late pass")
 +                        .takes_value(true)
 +                        .possible_values(&["early", "late"])
 +                        .required(true),
 +                )
 +                .arg(
 +                    Arg::with_name("name")
 +                        .short("n")
 +                        .long("name")
 +                        .help("Name of the new lint in snake case, ex: fn_too_long")
 +                        .takes_value(true)
 +                        .required(true),
 +                )
 +                .arg(
 +                    Arg::with_name("category")
 +                        .short("c")
 +                        .long("category")
 +                        .help("What category the lint belongs to")
 +                        .default_value("nursery")
 +                        .possible_values(&[
 +                            "style",
 +                            "correctness",
 +                            "suspicious",
 +                            "complexity",
 +                            "perf",
 +                            "pedantic",
 +                            "restriction",
 +                            "cargo",
 +                            "nursery",
 +                            "internal",
 +                            "internal_warn",
 +                        ])
 +                        .takes_value(true),
 +                )
 +                .arg(
 +                    Arg::with_name("msrv")
 +                        .long("msrv")
 +                        .help("Add MSRV config code to the lint"),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("setup")
 +                .about("Support for setting up your personal development environment")
 +                .setting(AppSettings::ArgRequiredElseHelp)
 +                .subcommand(
 +                    SubCommand::with_name("intellij")
 +                        .about("Alter dependencies so Intellij Rust can find rustc internals")
 +                        .arg(
 +                            Arg::with_name("rustc-repo-path")
 +                                .long("repo-path")
 +                                .short("r")
 +                                .help("The path to a rustc repo that will be used for setting the dependencies")
 +                                .takes_value(true)
 +                                .value_name("path")
 +                                .required(true),
 +                        ),
 +                )
 +                .subcommand(
 +                    SubCommand::with_name("git-hook")
 +                        .about("Add a pre-commit git hook that formats your code to make it look pretty")
 +                        .arg(
 +                            Arg::with_name("force-override")
 +                                .long("force-override")
 +                                .short("f")
 +                                .help("Forces the override of an existing git pre-commit hook")
 +                                .required(false),
 +                        ),
 +                )
 +                .subcommand(
 +                    SubCommand::with_name("vscode-tasks")
 +                        .about("Add several tasks to vscode for formatting, validation and testing")
 +                        .arg(
 +                            Arg::with_name("force-override")
 +                                .long("force-override")
 +                                .short("f")
 +                                .help("Forces the override of existing vscode tasks")
 +                                .required(false),
 +                        ),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("remove")
 +                .about("Support for undoing changes done by the setup command")
 +                .setting(AppSettings::ArgRequiredElseHelp)
 +                .subcommand(SubCommand::with_name("git-hook").about("Remove any existing pre-commit git hook"))
 +                .subcommand(SubCommand::with_name("vscode-tasks").about("Remove any existing vscode tasks"))
 +                .subcommand(
 +                    SubCommand::with_name("intellij")
 +                        .about("Removes rustc source paths added via `cargo dev setup intellij`"),
 +                ),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("serve")
 +                .about("Launch a local 'ALL the Clippy Lints' website in a browser")
 +                .arg(
 +                    Arg::with_name("port")
 +                        .long("port")
 +                        .short("p")
 +                        .help("Local port for the http server")
 +                        .default_value("8000")
 +                        .validator_os(serve::validate_port),
 +                )
 +                .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
 +        )
 +        .subcommand(
 +            SubCommand::with_name("lint")
-                     Arg::with_name("filename")
++                .about("Manually run clippy on a file or package")
++                .after_help(indoc! {"
++                    EXAMPLES
++                        Lint a single file:
++                            cargo dev lint tests/ui/attrs.rs
++
++                        Lint a package directory:
++                            cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
++                            cargo dev lint ~/my-project
++                "})
 +                .arg(
-                         .help("The path to a file to lint"),
++                    Arg::with_name("path")
 +                        .required(true)
++                        .help("The path to a file or package directory to lint"),
 +                ),
 +        )
 +        .get_matches()
 +}
index 59658b42c79b14405773817052214034e13cedbc,0000000000000000000000000000000000000000..7a3fd1317619e39d3021f8dafe8e0281dc4a99a1
mode 100644,000000..100644
--- /dev/null
@@@ -1,313 -1,0 +1,321 @@@
-     let mut command = cargo_metadata::MetadataCommand::new();
-     command.no_deps();
-     if let Ok(metadata) = command.exec() {
-         if let Some(pkg) = metadata.packages.iter().find(|pkg| pkg.name == "clippy") {
-             return format!("{}.{}.0", pkg.version.minor, pkg.version.patch);
-         }
 +use crate::clippy_project_root;
 +use indoc::indoc;
 +use std::fs::{self, OpenOptions};
 +use std::io::prelude::*;
 +use std::io::{self, ErrorKind};
 +use std::path::{Path, PathBuf};
 +
 +struct LintData<'a> {
 +    pass: &'a str,
 +    name: &'a str,
 +    category: &'a str,
 +    project_root: PathBuf,
 +}
 +
 +trait Context {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self;
 +}
 +
 +impl<T> Context for io::Result<T> {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self {
 +        match self {
 +            Ok(t) => Ok(t),
 +            Err(e) => {
 +                let message = format!("{}: {}", text.as_ref(), e);
 +                Err(io::Error::new(ErrorKind::Other, message))
 +            },
 +        }
 +    }
 +}
 +
 +/// Creates the files required to implement and test a new lint and runs `update_lints`.
 +///
 +/// # Errors
 +///
 +/// This function errors out if the files couldn't be created or written to.
 +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> {
 +    let lint = LintData {
 +        pass: pass.expect("`pass` argument is validated by clap"),
 +        name: lint_name.expect("`name` argument is validated by clap"),
 +        category: category.expect("`category` argument is validated by clap"),
 +        project_root: clippy_project_root(),
 +    };
 +
 +    create_lint(&lint, msrv).context("Unable to create lint implementation")?;
 +    create_test(&lint).context("Unable to create a test for the new lint")?;
 +    add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
 +}
 +
 +fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 +    let lint_contents = get_lint_file_contents(lint, enable_msrv);
 +
 +    let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
 +    write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
 +}
 +
 +fn create_test(lint: &LintData<'_>) -> io::Result<()> {
 +    fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
 +        let mut path = location.into().join(case);
 +        fs::create_dir(&path)?;
 +        write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
 +
 +        path.push("src");
 +        fs::create_dir(&path)?;
 +        let header = format!("// compile-flags: --crate-name={}", lint_name);
 +        write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
 +
 +        Ok(())
 +    }
 +
 +    if lint.category == "cargo" {
 +        let relative_test_dir = format!("tests/ui-cargo/{}", lint.name);
 +        let test_dir = lint.project_root.join(relative_test_dir);
 +        fs::create_dir(&test_dir)?;
 +
 +        create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
 +        create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")
 +    } else {
 +        let test_path = format!("tests/ui/{}.rs", lint.name);
 +        let test_contents = get_test_file_contents(lint.name, None);
 +        write_file(lint.project_root.join(test_path), test_contents)
 +    }
 +}
 +
 +fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 +    let path = "clippy_lints/src/lib.rs";
 +    let mut lib_rs = fs::read_to_string(path).context("reading")?;
 +
 +    let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
 +
 +    let new_lint = if enable_msrv {
 +        format!(
 +            "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
 +            lint_pass = lint.pass,
 +            module_name = lint.name,
 +            camel_name = to_camel_case(lint.name),
 +        )
 +    } else {
 +        format!(
 +            "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n    ",
 +            lint_pass = lint.pass,
 +            module_name = lint.name,
 +            camel_name = to_camel_case(lint.name),
 +        )
 +    };
 +
 +    lib_rs.insert_str(comment_start, &new_lint);
 +
 +    fs::write(path, lib_rs).context("writing")
 +}
 +
 +fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
 +    fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
 +        OpenOptions::new()
 +            .write(true)
 +            .create_new(true)
 +            .open(path)?
 +            .write_all(contents)
 +    }
 +
 +    inner(path.as_ref(), contents.as_ref()).context(format!("writing to file: {}", path.as_ref().display()))
 +}
 +
 +fn to_camel_case(name: &str) -> String {
 +    name.split('_')
 +        .map(|s| {
 +            if s.is_empty() {
 +                String::from("")
 +            } else {
 +                [&s[0..1].to_uppercase(), &s[1..]].concat()
 +            }
 +        })
 +        .collect()
 +}
 +
 +fn get_stabilisation_version() -> String {
-     String::from("<TODO set version(see doc/adding_lints.md)>")
++    fn parse_manifest(contents: &str) -> Option<String> {
++        let version = contents
++            .lines()
++            .filter_map(|l| l.split_once('='))
++            .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
++        let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
++            return None;
++        };
++        let (minor, patch) = version.split_once('.')?;
++        Some(format!(
++            "{}.{}.0",
++            minor.parse::<u32>().ok()?,
++            patch.parse::<u32>().ok()?
++        ))
 +    }
++    let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
++    parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
 +}
 +
 +fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
 +    let mut contents = format!(
 +        indoc! {"
 +            #![warn(clippy::{})]
 +
 +            fn main() {{
 +                // test code goes here
 +            }}
 +        "},
 +        lint_name
 +    );
 +
 +    if let Some(header) = header_commands {
 +        contents = format!("{}\n{}", header, contents);
 +    }
 +
 +    contents
 +}
 +
 +fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
 +    format!(
 +        indoc! {r#"
 +            # {}
 +
 +            [package]
 +            name = "{}"
 +            version = "0.1.0"
 +            publish = false
 +
 +            [workspace]
 +        "#},
 +        hint, lint_name
 +    )
 +}
 +
 +fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
 +    let mut result = String::new();
 +
 +    let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
 +        "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
 +        "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
 +        _ => {
 +            unreachable!("`pass_type` should only ever be `early` or `late`!");
 +        },
 +    };
 +
 +    let version = get_stabilisation_version();
 +    let lint_name = lint.name;
 +    let category = lint.category;
 +    let name_camel = to_camel_case(lint.name);
 +    let name_upper = lint_name.to_uppercase();
 +
 +    result.push_str(&if enable_msrv {
 +        format!(
 +            indoc! {"
 +                use clippy_utils::msrvs;
 +                {pass_import}
 +                use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
 +                use rustc_semver::RustcVersion;
 +                use rustc_session::{{declare_tool_lint, impl_lint_pass}};
 +
 +            "},
 +            pass_type = pass_type,
 +            pass_import = pass_import,
 +            context_import = context_import,
 +        )
 +    } else {
 +        format!(
 +            indoc! {"
 +                {pass_import}
 +                use rustc_lint::{{{context_import}, {pass_type}}};
 +                use rustc_session::{{declare_lint_pass, declare_tool_lint}};
 +
 +            "},
 +            pass_import = pass_import,
 +            pass_type = pass_type,
 +            context_import = context_import
 +        )
 +    });
 +
 +    result.push_str(&format!(
 +        indoc! {r#"
 +            declare_clippy_lint! {{
 +                /// ### What it does
 +                ///
 +                /// ### Why is this bad?
 +                ///
 +                /// ### Example
 +                /// ```rust
 +                /// // example code where clippy issues a warning
 +                /// ```
 +                /// Use instead:
 +                /// ```rust
 +                /// // example code which does not raise clippy warning
 +                /// ```
 +                #[clippy::version = "{version}"]
 +                pub {name_upper},
 +                {category},
 +                "default lint description"
 +            }}
 +        "#},
 +        version = version,
 +        name_upper = name_upper,
 +        category = category,
 +    ));
 +
 +    result.push_str(&if enable_msrv {
 +        format!(
 +            indoc! {"
 +                pub struct {name_camel} {{
 +                    msrv: Option<RustcVersion>,
 +                }}
 +
 +                impl {name_camel} {{
 +                    #[must_use]
 +                    pub fn new(msrv: Option<RustcVersion>) -> Self {{
 +                        Self {{ msrv }}
 +                    }}
 +                }}
 +
 +                impl_lint_pass!({name_camel} => [{name_upper}]);
 +
 +                impl {pass_type}{pass_lifetimes} for {name_camel} {{
 +                    extract_msrv_attr!({context_import});
 +                }}
 +
 +                // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
 +                // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
 +                // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
 +            "},
 +            pass_type = pass_type,
 +            pass_lifetimes = pass_lifetimes,
 +            name_upper = name_upper,
 +            name_camel = name_camel,
 +            context_import = context_import,
 +        )
 +    } else {
 +        format!(
 +            indoc! {"
 +                declare_lint_pass!({name_camel} => [{name_upper}]);
 +
 +                impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
 +            "},
 +            pass_type = pass_type,
 +            pass_lifetimes = pass_lifetimes,
 +            name_upper = name_upper,
 +            name_camel = name_camel,
 +        )
 +    });
 +
 +    result
 +}
 +
 +#[test]
 +fn test_camel_case() {
 +    let s = "a_lint";
 +    let s2 = to_camel_case(s);
 +    assert_eq!(s2, "ALint");
 +
 +    let name = "a_really_long_new_lint";
 +    let name2 = to_camel_case(name);
 +    assert_eq!(name2, "AReallyLongNewLint");
 +
 +    let name3 = "lint__name";
 +    let name4 = to_camel_case(name3);
 +    assert_eq!(name4, "LintName");
 +}
index d368ef1f46a2a98866e6aedcf32581c9ce17c047,0000000000000000000000000000000000000000..59db51fbfac5149fec5158a137c91e94fa86bf4b
mode 100644,000000..100644
--- /dev/null
@@@ -1,710 -1,0 +1,604 @@@
- use regex::Regex;
++use core::fmt::Write;
 +use itertools::Itertools;
- use std::lazy::SyncLazy;
++use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 +use std::collections::HashMap;
 +use std::ffi::OsStr;
 +use std::fs;
- static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
-     Regex::new(
-         r#"(?x)
-     declare_clippy_lint!\s*[\{(]
-     (?:\s+///.*)*
-     (?:\s*\#\[clippy::version\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*\#\[clippy::version\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";
 +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";
 +
-     let lint_list: Vec<Lint> = gather_all().collect();
++const 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 internal_lints = Lint::internal_lints(&lint_list);
-     let deprecated_lints = Lint::deprecated_lints(&lint_list);
-     let usable_lints = Lint::usable_lints(&lint_list);
++    let (lints, deprecated_lints) = gather_all();
 +
-     let usable_lint_count = round_to_fifty(usable_lints.len());
-     let mut file_change = false;
-     file_change |= replace_region_in_file(
++    let internal_lints = Lint::internal_lints(&lints);
++    let usable_lints = Lint::usable_lints(&lints);
 +    let mut sorted_usable_lints = usable_lints.clone();
 +    sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
 +
-         &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
-             )]
++    replace_region_in_file(
++        update_mode,
 +        Path::new("README.md"),
-     )
-     .changed;
++        "[There are over ",
++        " lints included in this crate!]",
++        |res| {
++            write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap();
 +        },
-     file_change |= replace_region_in_file(
++    );
 +
-         "<!-- begin autogenerated links to lint list -->",
++    replace_region_in_file(
++        update_mode,
 +        Path::new("CHANGELOG.md"),
-         false,
-         update_mode == UpdateMode::Change,
-         || gen_changelog_lint_list(usable_lints.iter().chain(deprecated_lints.iter())),
-     )
-     .changed;
++        "<!-- begin autogenerated links to lint list -->\n",
 +        "<!-- end autogenerated links to lint list -->",
-     file_change |= replace_region_in_file(
++        |res| {
++            for lint in usable_lints
++                .iter()
++                .map(|l| &l.name)
++                .chain(deprecated_lints.iter().map(|l| &l.name))
++                .sorted()
++            {
++                writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap();
++            }
++        },
++    );
 +
 +    // This has to be in lib.rs, otherwise rustfmt doesn't work
-         "begin lints modules",
-         "end lints modules",
-         false,
-         update_mode == UpdateMode::Change,
-         || gen_modules_list(usable_lints.iter()),
-     )
-     .changed;
-     if file_change && update_mode == UpdateMode::Check {
-         exit_with_failure();
-     }
++    replace_region_in_file(
++        update_mode,
 +        Path::new("clippy_lints/src/lib.rs"),
-         &gen_deprecated(deprecated_lints.iter()),
++        "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n",
++        "// end lints modules, do not remove this comment, it’s used in `update_lints`",
++        |res| {
++            for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() {
++                writeln!(res, "mod {};", lint_mod).unwrap();
++            }
++        },
++    );
 +
 +    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,
-     let lint_list: Vec<Lint> = gather_all().collect();
++        &gen_deprecated(&deprecated_lints),
 +    );
 +
 +    let all_group_lints = usable_lints.iter().filter(|l| {
 +        matches!(
 +            &*l.group,
 +            "correctness" | "suspicious" | "style" | "complexity" | "perf"
 +        )
 +    });
 +    let content = gen_lint_group_list("all", all_group_lints);
 +    process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
 +
 +    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,
 +        );
 +    }
 +}
 +
 +pub fn print_lints() {
-         if lint_group == "Deprecated" {
-             continue;
-         }
++    let (lint_list, _) = gather_all();
 +    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 {
-     deprecation: Option<String>,
 +        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,
-     fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
 +    module: String,
 +}
 +
 +impl Lint {
 +    #[must_use]
-             group: group.to_string(),
-             desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
-             deprecation: deprecation.map(ToString::to_string),
-             module: module.to_string(),
++    fn new(name: &str, group: &str, desc: &str, module: &str) -> Self {
 +        Self {
 +            name: name.to_lowercase(),
-             .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal"))
++            group: group.into(),
++            desc: remove_line_splices(desc),
++            module: module.into(),
 +        }
 +    }
 +
 +    /// Returns all non-deprecated lints and non-internal lints
 +    #[must_use]
 +    fn usable_lints(lints: &[Self]) -> Vec<Self> {
 +        lints
 +            .iter()
-     /// Returns all deprecated lints
-     #[must_use]
-     fn deprecated_lints(lints: &[Self]) -> Vec<Self> {
-         lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect()
-     }
++            .filter(|l| !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()
 +    }
 +
- /// 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()
- }
 +    /// 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()
 +    }
 +}
 +
++#[derive(Clone, PartialEq, Debug)]
++struct DeprecatedLint {
++    name: String,
++    reason: String,
++}
++impl DeprecatedLint {
++    fn new(name: &str, reason: &str) -> Self {
++        Self {
++            name: name.to_lowercase(),
++            reason: remove_line_splices(reason),
++        }
++    }
++}
++
 +/// 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
 +}
 +
- fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> String {
 +/// Generates the `register_removed` code
 +#[must_use]
-     for Lint { name, deprecation, .. } in lints {
++fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
 +    let mut output = GENERATED_FILE_COMMENT.to_string();
 +    output.push_str("{\n");
-             name,
-             deprecation.as_ref().expect("`lints` are deprecated")
++    for lint in lints {
 +        output.push_str(&format!(
 +            concat!(
 +                "    store.register_removed(\n",
 +                "        \"clippy::{}\",\n",
 +                "        \"{}\",\n",
 +                "    );\n"
 +            ),
- /// 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))
- }
++            lint.name, lint.reason,
 +        ));
 +    }
 +    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\")]\n");
 +        }
 +        output.push_str(&format!("    {}::{},\n", module_name, lint_name));
 +    }
 +    output.push_str("])\n");
 +
 +    output
 +}
 +
- 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();
-     }
++/// Gathers all lints defined in `clippy_lints/src`
++fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>) {
++    let mut lints = Vec::with_capacity(1000);
++    let mut deprecated_lints = Vec::with_capacity(50);
++    let root_path = clippy_project_root().join("clippy_lints/src");
 +
-     let module = rel_path
-         .components()
-         .map(|c| c.as_os_str().to_str().unwrap())
-         .collect::<Vec<_>>()
-         .join("::");
++    for (rel_path, file) in WalkDir::new(&root_path)
++        .into_iter()
++        .map(Result::unwrap)
++        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
++        .map(|f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f))
++    {
++        let path = file.path();
++        let contents =
++            fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
++        let module = rel_path
++            .components()
++            .map(|c| c.as_os_str().to_str().unwrap())
++            .collect::<Vec<_>>()
++            .join("::");
++
++        // If the lints are stored in mod.rs, we get the module name from
++        // the containing directory:
++        let module = if let Some(module) = module.strip_suffix("::mod.rs") {
++            module
++        } else {
++            module.strip_suffix(".rs").unwrap_or(&module)
++        };
 +
-     parse_contents(&content, &module)
++        if module == "deprecated_lints" {
++            parse_deprecated_contents(&contents, &mut deprecated_lints);
++        } else {
++            parse_contents(&contents, module, &mut lints);
++        }
++    }
++    (lints, deprecated_lints)
++}
 +
- 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()
++macro_rules! match_tokens {
++    ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => {
++         {
++            $($(let $capture =)? if let Some((TokenKind::$token $({$($fields)*})?, _x)) = $iter.next() {
++                _x
++            } else {
++                continue;
++            };)*
++            #[allow(clippy::unused_unit)]
++            { ($($($capture,)?)*) }
++        }
++    }
 +}
 +
- /// 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")))
++/// Parse a source file looking for `declare_clippy_lint` macro invocations.
++fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
++    let mut offset = 0usize;
++    let mut iter = tokenize(contents).map(|t| {
++        let range = offset..offset + t.len;
++        offset = range.end;
++        (t.kind, &contents[range])
++    });
++
++    while iter.any(|(kind, s)| kind == TokenKind::Ident && s == "declare_clippy_lint") {
++        let mut iter = iter
++            .by_ref()
++            .filter(|&(kind, _)| !matches!(kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
++        // matches `!{`
++        match_tokens!(iter, Bang OpenBrace);
++        match iter.next() {
++            // #[clippy::version = "version"] pub
++            Some((TokenKind::Pound, _)) => {
++                match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
++            },
++            // pub
++            Some((TokenKind::Ident, _)) => (),
++            _ => continue,
++        }
++        let (name, group, desc) = match_tokens!(
++            iter,
++            // LINT_NAME
++            Ident(name) Comma
++            // group,
++            Ident(group) Comma
++            // "description" }
++            Literal{..}(desc) CloseBrace
++        );
++        lints.push(Lint::new(name, group, desc, module));
++    }
 +}
 +
- /// Whether a file has had its text changed or not
- #[derive(PartialEq, Debug)]
- struct FileChange {
-     changed: bool,
-     new_lines: String,
++/// Parse a source file looking for `declare_deprecated_lint` macro invocations.
++fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
++    let mut offset = 0usize;
++    let mut iter = tokenize(contents).map(|t| {
++        let range = offset..offset + t.len;
++        offset = range.end;
++        (t.kind, &contents[range])
++    });
++    while iter.any(|(kind, s)| kind == TokenKind::Ident && s == "declare_deprecated_lint") {
++        let mut iter = iter
++            .by_ref()
++            .filter(|&(kind, _)| !matches!(kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
++        let (name, reason) = match_tokens!(
++            iter,
++            // !{
++            Bang OpenBrace
++            // #[clippy::version = "version"]
++            Pound OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket
++            // pub LINT_NAME,
++            Ident Ident(name) Comma
++            // "description"
++            Literal{kind: LiteralKind::Str{..},..}(reason)
++            // }
++            CloseBrace
++        );
++        lints.push(DeprecatedLint::new(name, reason));
++    }
 +}
 +
- fn replace_region_in_file<F>(
++/// Removes the line splices and surrounding quotes from a string literal
++fn remove_line_splices(s: &str) -> String {
++    let s = s
++        .strip_prefix('r')
++        .unwrap_or(s)
++        .trim_matches('#')
++        .strip_prefix('"')
++        .and_then(|s| s.strip_suffix('"'))
++        .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s));
++    let mut res = String::with_capacity(s.len());
++    unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range]));
++    res
 +}
 +
 +/// 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
-     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());
++fn replace_region_in_file(
++    update_mode: UpdateMode,
 +    path: &Path,
 +    start: &str,
 +    end: &str,
-             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');
++    write_replacement: impl FnMut(&mut String),
++) {
++    let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
++    let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
++        Ok(x) => x,
++        Err(delim) => panic!("Couldn't find `{}` in file `{}`", delim, path.display()),
++    };
++
++    match update_mode {
++        UpdateMode::Check if contents != new_contents => exit_with_failure(),
++        UpdateMode::Check => (),
++        UpdateMode::Change => {
++            if let Err(e) = fs::write(path, new_contents.as_bytes()) {
++                panic!("Cannot write to `{}`: {}", path.display(), e);
 +            }
-     let changed = new_lines != text;
-     FileChange { changed, new_lines }
- }
- #[test]
- fn test_parse_contents() {
-     let result: Vec<Lint> = parse_contents(
-         r#"
- declare_clippy_lint! {
-     #[clippy::version = "Hello Clippy!"]
-     pub PTR_ARG,
-     style,
-     "really long \
-      text"
++        },
 +    }
- declare_clippy_lint!{
-     #[clippy::version = "Test version"]
-     pub DOC_MARKDOWN,
-     pedantic,
-     "single line"
- }
- /// some doc comment
- declare_deprecated_lint! {
-     #[clippy::version = "I'm a version"]
-     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);
 +}
 +
-     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);
-     }
++/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
++/// were found, or the missing delimiter if not.
++fn replace_region_in_text<'a>(
++    text: &str,
++    start: &'a str,
++    end: &'a str,
++    mut write_replacement: impl FnMut(&mut String),
++) -> Result<String, &'a str> {
++    let (text_start, rest) = text.split_once(start).ok_or(start)?;
++    let (_, text_end) = rest.split_once(end).ok_or(end)?;
++
++    let mut res = String::with_capacity(text.len() + 4096);
++    res.push_str(text_start);
++    res.push_str(start);
++    write_replacement(&mut res);
++    res.push_str(end);
++    res.push_str(text_end);
++
++    Ok(res)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    #[test]
-     #[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()]
-         });
++    fn test_parse_contents() {
++        static CONTENTS: &str = r#"
++            declare_clippy_lint! {
++                #[clippy::version = "Hello Clippy!"]
++                pub PTR_ARG,
++                style,
++                "really long \
++                text"
++            }
 +
-     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);
++            declare_clippy_lint!{
++                #[clippy::version = "Test version"]
++                pub DOC_MARKDOWN,
++                pedantic,
++                "single line"
++            }
++        "#;
++        let mut result = Vec::new();
++        parse_contents(CONTENTS, "module_name", &mut result);
++
++        let expected = vec![
++            Lint::new("ptr_arg", "style", "\"really long text\"", "module_name"),
++            Lint::new("doc_markdown", "pedantic", "\"single line\"", "module_name"),
++        ];
 +        assert_eq!(expected, result);
 +    }
 +
 +    #[test]
-             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"),
++    fn test_parse_deprecated_contents() {
++        static DEPRECATED_CONTENTS: &str = r#"
++            /// some doc comment
++            declare_deprecated_lint! {
++                #[clippy::version = "I'm a version"]
++                pub SHOULD_ASSERT_EQ,
++                "`assert!()` will be more flexible with RFC 2011"
++            }
++        "#;
++
++        let mut result = Vec::new();
++        parse_deprecated_contents(DEPRECATED_CONTENTS, &mut result);
++
++        let expected = vec![DeprecatedLint::new(
++            "should_assert_eq",
++            "\"`assert!()` will be more flexible with RFC 2011\"",
++        )];
 +        assert_eq!(expected, result);
 +    }
 +
 +    #[test]
 +    fn test_usable_lints() {
 +        let lints = vec![
-             "abc",
-             None,
++            Lint::new("should_assert_eq2", "Not Deprecated", "\"abc\"", "module_name"),
++            Lint::new("should_assert_eq2", "internal", "\"abc\"", "module_name"),
++            Lint::new("should_assert_eq2", "internal_style", "\"abc\"", "module_name"),
 +        ];
 +        let expected = vec![Lint::new(
 +            "should_assert_eq2",
 +            "Not Deprecated",
-             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"),
++            "\"abc\"",
 +            "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("incorrect_match", "group1", "abc", None, "module_name"),
++            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"),
++            Lint::new("should_assert_eq2", "group2", "\"abc\"", "module_name"),
++            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name"),
 +        ];
 +        let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
 +        expected.insert(
 +            "group1".to_string(),
 +            vec![
-             vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
++                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"),
++                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name"),
 +            ],
 +        );
 +        expected.insert(
 +            "group2".to_string(),
-     #[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),
-             format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK),
-         ];
-         assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
-     }
++            vec![Lint::new("should_assert_eq2", "group2", "\"abc\"", "module_name")],
 +        );
 +        assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
 +    }
 +
-             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",
-             ),
 +    #[test]
 +    fn test_gen_deprecated() {
 +        let lints = vec![
-         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()));
++            DeprecatedLint::new("should_assert_eq", "\"has been superseded by should_assert_eq2\""),
++            DeprecatedLint::new("another_deprecated", "\"will be removed\""),
 +        ];
 +
 +        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";
 +
-             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"),
++        assert_eq!(expected, gen_deprecated(&lints));
 +    }
 +
 +    #[test]
 +    fn test_gen_lint_group_list() {
 +        let lints = vec![
++            Lint::new("abc", "group1", "\"abc\"", "module_name"),
++            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"),
++            Lint::new("internal", "internal_style", "\"abc\"", "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 66e61660d313aa150e1fcbb9106fce4d83bc7ffe,0000000000000000000000000000000000000000..aebf9a87cabd2c7369816bbfcb7386eea0cba6fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,37 @@@
- version = "0.1.61"
 +[package]
 +name = "clippy_lints"
++version = "0.1.62"
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +edition = "2021"
 +
 +[dependencies]
 +cargo_metadata = "0.14"
 +clippy_utils = { path = "../clippy_utils" }
 +if_chain = "1.0"
 +itertools = "0.10.1"
 +pulldown-cmark = { version = "0.9", default-features = false }
 +quine-mc_cluskey = "0.2"
 +regex-syntax = "0.6"
 +serde = { version = "1.0", features = ["derive"] }
 +serde_json = { version = "1.0", optional = true }
 +toml = "0.5"
 +unicode-normalization = "0.1"
 +unicode-script = { version = "0.5", default-features = false }
 +semver = "1.0"
 +rustc-semver = "1.1"
 +# NOTE: cargo requires serde feat in its url dep
 +# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
 +url = { version = "2.2", features = ["serde"] }
 +
 +[features]
 +deny-warnings = ["clippy_utils/deny-warnings"]
 +# build clippy with internal lints enabled, off by default
 +internal = ["clippy_utils/internal", "serde_json"]
 +
 +[package.metadata.rust-analyzer]
 +# This crate uses #[feature(rustc_private)]
 +rustc_private = true
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e9b0f1f672de0bb06e6178fa95746c3aba60d600
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::sugg::Sugg;
++use clippy_utils::{meets_msrv, msrvs};
++use if_chain::if_chain;
++use rustc_errors::Applicability;
++use rustc_hir::{Expr, ExprKind};
++use rustc_lint::LateContext;
++use rustc_middle::ty::Ty;
++use rustc_semver::RustcVersion;
++
++use super::CAST_ABS_TO_UNSIGNED;
++
++pub(super) fn check(
++    cx: &LateContext<'_>,
++    expr: &Expr<'_>,
++    cast_expr: &Expr<'_>,
++    cast_from: Ty<'_>,
++    cast_to: Ty<'_>,
++    msrv: &Option<RustcVersion>,
++) {
++    if_chain! {
++        if meets_msrv(msrv.as_ref(), &msrvs::UNSIGNED_ABS);
++        if cast_from.is_integral();
++        if cast_to.is_integral();
++        if cast_from.is_signed();
++        if !cast_to.is_signed();
++        if let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind;
++        if let method_name = method_path.ident.name.as_str();
++        if method_name == "abs";
++        then {
++            span_lint_and_sugg(
++                cx,
++                CAST_ABS_TO_UNSIGNED,
++                expr.span,
++                &format!("casting the result of `{}::{}()` to {}", cast_from, method_name, cast_to),
++                "replace with",
++                format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
++                Applicability::MachineApplicable,
++            );
++        }
++    }
++}
index a4ef1344ab9511beb75790081393d1e456c98040,0000000000000000000000000000000000000000..d476a1a7646c01e24bd8ea9b3df3297ec980fdba
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,96 @@@
- use clippy_utils::is_hir_ty_cfg_dependant;
 +use clippy_utils::diagnostics::span_lint;
- use if_chain::if_chain;
 +use clippy_utils::ty::is_c_void;
-         if_chain! {
-             if method_path.ident.name == sym!(cast);
-             if let Some(generic_args) = method_path.args;
-             if let [GenericArg::Type(cast_to)] = generic_args.args;
++use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths};
 +use rustc_hir::{Expr, ExprKind, GenericArg};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::layout::LayoutOf;
 +use rustc_middle::ty::{self, Ty};
 +
 +use super::CAST_PTR_ALIGNMENT;
 +
 +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +    if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
 +        if is_hir_ty_cfg_dependant(cx, cast_to) {
 +            return;
 +        }
 +        let (cast_from, cast_to) = (
 +            cx.typeck_results().expr_ty(cast_expr),
 +            cx.typeck_results().expr_ty(expr),
 +        );
 +        lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
 +    } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
-             if !is_hir_ty_cfg_dependant(cx, cast_to);
-             then {
-                 let (cast_from, cast_to) =
-                     (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
-                 lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
-             }
++        if method_path.ident.name == sym!(cast)
++            && let Some(generic_args) = method_path.args
++            && let [GenericArg::Type(cast_to)] = generic_args.args
 +            // There probably is no obvious reason to do this, just to be consistent with `as` cases.
-     if_chain! {
-         if let ty::RawPtr(from_ptr_ty) = &cast_from.kind();
-         if let ty::RawPtr(to_ptr_ty) = &cast_to.kind();
-         if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty);
-         if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty);
-         if from_layout.align.abi < to_layout.align.abi;
++            && !is_hir_ty_cfg_dependant(cx, cast_to)
++        {
++            let (cast_from, cast_to) =
++                (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
++            lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
 +        }
 +    }
 +}
 +
 +fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
-         if !is_c_void(cx, from_ptr_ty.ty);
++    if let ty::RawPtr(from_ptr_ty) = &cast_from.kind()
++        && let ty::RawPtr(to_ptr_ty) = &cast_to.kind()
++        && let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty)
++        && let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty)
++        && from_layout.align.abi < to_layout.align.abi
 +        // with c_void, we inherently need to trust the user
-         if !from_layout.is_zst();
-         then {
-             span_lint(
-                 cx,
-                 CAST_PTR_ALIGNMENT,
-                 expr.span,
-                 &format!(
-                     "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
-                     cast_from,
-                     cast_to,
-                     from_layout.align.abi.bytes(),
-                     to_layout.align.abi.bytes(),
-                 ),
-             );
-         }
++        && !is_c_void(cx, from_ptr_ty.ty)
 +        // when casting from a ZST, we don't know enough to properly lint
++        && !from_layout.is_zst()
++        && !is_used_as_unaligned(cx, expr)
++    {
++        span_lint(
++            cx,
++            CAST_PTR_ALIGNMENT,
++            expr.span,
++            &format!(
++                "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
++                cast_from,
++                cast_to,
++                from_layout.align.abi.bytes(),
++                to_layout.align.abi.bytes(),
++            ),
++        );
++    }
++}
++
++fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
++    let Some(parent) = get_parent_expr(cx, e) else {
++        return false;
++    };
++    match parent.kind {
++        ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
++            if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
++                && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
++                && let Some(def_id) = cx.tcx.impl_of_method(def_id)
++                && cx.tcx.type_of(def_id).is_unsafe_ptr()
++            {
++                true
++            } else {
++                false
++            }
++        },
++        ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => {
++            static PATHS: &[&[&str]] = &[
++                paths::PTR_READ_UNALIGNED.as_slice(),
++                paths::PTR_WRITE_UNALIGNED.as_slice(),
++                paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(),
++                paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(),
++            ];
++            if let ExprKind::Path(path) = &func.kind
++                && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
++                && match_any_def_paths(cx, def_id, PATHS).is_some()
++            {
++                true
++            } else {
++                false
++            }
++        },
++        _ => false,
 +    }
 +}
index be59145afa0032a3cd7c8882c770dd48f4a53288,0000000000000000000000000000000000000000..55c1f085657bb1842eafd7c52ff5e75a5b68321c
mode 100644,000000..100644
--- /dev/null
@@@ -1,553 -1,0 +1,578 @@@
-     CAST_ENUM_CONSTRUCTOR
++mod cast_abs_to_unsigned;
 +mod cast_enum_constructor;
 +mod cast_lossless;
 +mod cast_possible_truncation;
 +mod cast_possible_wrap;
 +mod cast_precision_loss;
 +mod cast_ptr_alignment;
 +mod cast_ref_to_mut;
 +mod cast_sign_loss;
 +mod cast_slice_different_sizes;
 +mod char_lit_as_u8;
 +mod fn_to_numeric_cast;
 +mod fn_to_numeric_cast_any;
 +mod fn_to_numeric_cast_with_truncation;
 +mod ptr_as_ptr;
 +mod unnecessary_cast;
 +mod utils;
 +
 +use clippy_utils::is_hir_ty_cfg_dependant;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from any numerical to a float type where
 +    /// the receiving type cannot store all values from the original type without
 +    /// rounding errors. This possible rounding is to be expected, so this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// Basically, this warns on casting any integer with 32 or more bits to `f32`
 +    /// or any 64-bit integer to `f64`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not bad at all. But in some applications it can be
 +    /// helpful to know where precision loss can take place. This lint can help find
 +    /// those places in the code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = u64::MAX;
 +    /// x as f64;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_PRECISION_LOSS,
 +    pedantic,
 +    "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from a signed to an unsigned numerical
 +    /// type. In this case, negative values wrap around to large positive values,
 +    /// which can be quite surprising in practice. However, as the cast works as
 +    /// defined, this lint is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// Possibly surprising results. You can activate this lint
 +    /// as a one-time check to see where numerical wrapping can arise.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let y: i8 = -1;
 +    /// y as u128; // will return 18446744073709551615
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_SIGN_LOSS,
 +    pedantic,
 +    "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// truncate large values. This is expected behavior, so the cast is `Allow` by
 +    /// default.
 +    ///
 +    /// ### Why is this bad?
 +    /// In some problem domains, it is good practice to avoid
 +    /// truncation. This lint can be activated to help assess where additional
 +    /// checks could be beneficial.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u8(x: u64) -> u8 {
 +    ///     x as u8
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_POSSIBLE_TRUNCATION,
 +    pedantic,
 +    "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an unsigned type to a signed type of
 +    /// the same size. Performing such a cast is a 'no-op' for the compiler,
 +    /// i.e., nothing is changed at the bit level, and the binary representation of
 +    /// the value is reinterpreted. This can cause wrapping if the value is too big
 +    /// for the target signed type. However, the cast works as defined, so this lint
 +    /// is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// While such a cast is not bad in itself, the results can
 +    /// be surprising when this is not the intended behavior, as demonstrated by the
 +    /// example below.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// u32::MAX as i32; // will yield a value of `-1`
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_POSSIBLE_WRAP,
 +    pedantic,
 +    "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// be replaced by safe conversion functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// Rust's `as` keyword will perform many kinds of
 +    /// conversions, including silently lossy conversions. Conversion functions such
 +    /// as `i32::from` will only perform lossless conversions. Using the conversion
 +    /// functions prevents conversions from turning into silent lossy conversions if
 +    /// the types of the input expressions ever change, and make it easier for
 +    /// people reading the code to know that the conversion is lossless.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     x as u64
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `::from` would look like this:
 +    ///
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     u64::from(x)
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_LOSSLESS,
 +    pedantic,
 +    "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts to the same type, casts of int literals to integer types
 +    /// and casts of float literals to float types.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's just unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = 2i32 as i32;
 +    /// let _ = 0.5 as f32;
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// let _ = 2_i32;
 +    /// let _ = 0.5_f32;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNNECESSARY_CAST,
 +    complexity,
 +    "cast to the same type, e.g., `x as i32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts, using `as` or `pointer::cast`,
 +    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
 +    ///
 +    /// ### Why is this bad?
 +    /// Dereferencing the resulting pointer may be undefined
 +    /// behavior.
 +    ///
 +    /// ### Known problems
 +    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
 +    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
 +    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (&1u8 as *const u8) as *const u16;
 +    /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
 +    ///
 +    /// (&1u8 as *const u8).cast::<u16>();
 +    /// (&mut 1u8 as *mut u8).cast::<u16>();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CAST_PTR_ALIGNMENT,
 +    pedantic,
 +    "cast from a pointer to a more-strictly-aligned pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of function pointers to something other than usize
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to anything other than usize/isize is not portable across
 +    /// architectures, because you end up losing bits if the target type is too small or end up with a
 +    /// bunch of extra bits that waste space and add more instructions to the final binary than
 +    /// strictly necessary for the problem
 +    ///
 +    /// Casting to isize also doesn't make sense since there are no signed addresses.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// fn fun() -> i32 { 1 }
 +    /// let a = fun as i64;
 +    ///
 +    /// // Good
 +    /// fn fun2() -> i32 { 1 }
 +    /// let a = fun2 as usize;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FN_TO_NUMERIC_CAST,
 +    style,
 +    "casting a function pointer to a numeric type other than usize"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to a numeric type not wide enough to
 +    /// store address.
 +    ///
 +    /// ### Why is this bad?
 +    /// Such a cast discards some bits of the function's address. If this is intended, it would be more
 +    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
 +    /// a comment) to perform the truncation.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// fn fn1() -> i16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as i32;
 +    ///
 +    /// // Better: Cast to usize first, then comment with the reason for the truncation
 +    /// fn fn2() -> i16 {
 +    ///     1
 +    /// };
 +    /// let fn_ptr = fn2 as usize;
 +    /// let fn_ptr_truncated = fn_ptr as i32;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    style,
 +    "casting a function pointer to a numeric type not wide enough to store the address"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to any integer type.
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to an integer can have surprising results and can occur
 +    /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
 +    /// low-level with function pointers then you can opt-out of casting functions to integers in
 +    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
 +    /// pointer casts in your code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad: fn1 is cast as `usize`
 +    /// fn fn1() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as usize;
 +    ///
 +    /// // Good: maybe you intended to call the function?
 +    /// fn fn2() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn2() as usize;
 +    ///
 +    /// // Good: maybe you intended to cast it to a function type?
 +    /// fn fn3() -> u16 {
 +    ///     1
 +    /// }
 +    /// let _ = fn3 as fn() -> u16;
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub FN_TO_NUMERIC_CAST_ANY,
 +    restriction,
 +    "casting a function pointer to any integer type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of `&T` to `&mut T` anywhere in the code.
 +    ///
 +    /// ### Why is this bad?
 +    /// It’s basically guaranteed to be undefined behaviour.
 +    /// `UnsafeCell` is the only way to obtain aliasable data that is considered
 +    /// mutable.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// fn x(r: &i32) {
 +    ///     unsafe {
 +    ///         *(r as *const _ as *mut _) += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Instead consider using interior mutability types.
 +    ///
 +    /// ```rust
 +    /// use std::cell::UnsafeCell;
 +    ///
 +    /// fn x(r: &UnsafeCell<i32>) {
 +    ///     unsafe {
 +    ///         *r.get() += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.33.0"]
 +    pub CAST_REF_TO_MUT,
 +    correctness,
 +    "a cast of reference to a mutable pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions where a character literal is cast
 +    /// to `u8` and suggests using a byte literal instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// In general, casting values to smaller types is
 +    /// error-prone and should be avoided where possible. In the particular case of
 +    /// converting a character literal to u8, it is easy to avoid by just using a
 +    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
 +    /// than `'a' as u8`.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// 'x' as u8
 +    /// ```
 +    ///
 +    /// A better version, using the byte literal:
 +    ///
 +    /// ```rust,ignore
 +    /// b'x'
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHAR_LIT_AS_U8,
 +    complexity,
 +    "casting a character literal to `u8` truncates"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `as` casts between raw pointers without changing its mutability,
 +    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
 +    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr as *const i32;
 +    /// let _ = mut_ptr as *mut i32;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr.cast::<i32>();
 +    /// let _ = mut_ptr.cast::<i32>();
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub PTR_AS_PTR,
 +    pedantic,
 +    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an enum type to an integral type which will definitely truncate the
 +    /// value.
 +    ///
 +    /// ### Why is this bad?
 +    /// The resulting integral value will not match the value of the variant it came from.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum E { X = 256 };
 +    /// let _ = E::X as u8;
 +    /// ```
 +    #[clippy::version = "1.60.0"]
 +    pub CAST_ENUM_TRUNCATION,
 +    suspicious,
 +    "casts from an enum type to an integral type which will truncate the value"
 +}
 +
 +declare_clippy_lint! {
 +    /// Checks for `as` casts between raw pointers to slices with differently sized elements.
 +    ///
 +    /// ### Why is this bad?
 +    /// The produced raw pointer to a slice does not update its length metadata. The produced
 +    /// pointer will point to a different number of bytes than the original pointer because the
 +    /// length metadata of a raw slice pointer is in elements rather than bytes.
 +    /// Producing a slice reference from the raw pointer will either create a slice with
 +    /// less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
 +    ///
 +    /// ### Example
 +    /// // Missing data
 +    /// ```rust
 +    /// let a = [1_i32, 2, 3, 4];
 +    /// let p = &a as *const [i32] as *const [u8];
 +    /// unsafe {
 +    ///     println!("{:?}", &*p);
 +    /// }
 +    /// ```
 +    /// // Undefined Behavior (note: also potential alignment issues)
 +    /// ```rust
 +    /// let a = [1_u8, 2, 3, 4];
 +    /// let p = &a as *const [u8] as *const [u32];
 +    /// unsafe {
 +    ///     println!("{:?}", &*p);
 +    /// }
 +    /// ```
 +    /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
 +    /// ```rust
 +    /// let a = [1_i32, 2, 3, 4];
 +    /// let old_ptr = &a as *const [i32];
 +    /// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
 +    /// // The length comes from the known length of 4 i32s times the 4 bytes per i32
 +    /// let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
 +    /// unsafe {
 +    ///     println!("{:?}", &*new_ptr);
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.60.0"]
 +    pub CAST_SLICE_DIFFERENT_SIZES,
 +    correctness,
 +    "casting using `as` between raw pointers to slices of types with different sizes"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an enum tuple constructor to an integer.
 +    ///
 +    /// ### Why is this bad?
 +    /// The cast is easily confused with casting a c-like enum value to an integer.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum E { X(i32) };
 +    /// let _ = E::X as usize;
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub CAST_ENUM_CONSTRUCTOR,
 +    suspicious,
 +    "casts from an enum tuple constructor to an integer"
 +}
 +
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for uses of the `abs()` method that cast the result to unsigned.
++    ///
++    /// ### Why is this bad?
++    /// The `unsigned_abs()` method avoids panic when called on the MIN value.
++    ///
++    /// ### Example
++    /// ```rust
++    /// let x: i32 = -42;
++    /// let y: u32 = x.abs() as u32;
++    /// ```
++    /// Use instead:
++    /// let x: i32 = -42;
++    /// let y: u32 = x.unsigned_abs();
++    /// ```
++    #[clippy::version = "1.61.0"]
++    pub CAST_ABS_TO_UNSIGNED,
++    suspicious,
++    "casting the result of `abs()` to an unsigned integer can panic"
++}
++
 +pub struct Casts {
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl Casts {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(Casts => [
 +    CAST_PRECISION_LOSS,
 +    CAST_SIGN_LOSS,
 +    CAST_POSSIBLE_TRUNCATION,
 +    CAST_POSSIBLE_WRAP,
 +    CAST_LOSSLESS,
 +    CAST_REF_TO_MUT,
 +    CAST_PTR_ALIGNMENT,
 +    CAST_SLICE_DIFFERENT_SIZES,
 +    UNNECESSARY_CAST,
 +    FN_TO_NUMERIC_CAST_ANY,
 +    FN_TO_NUMERIC_CAST,
 +    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    CHAR_LIT_AS_U8,
 +    PTR_AS_PTR,
 +    CAST_ENUM_TRUNCATION,
++    CAST_ENUM_CONSTRUCTOR,
++    CAST_ABS_TO_UNSIGNED
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Casts {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if !in_external_macro(cx.sess(), expr.span) {
 +            ptr_as_ptr::check(cx, expr, &self.msrv);
 +        }
 +
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
 +            if is_hir_ty_cfg_dependant(cx, cast_to) {
 +                return;
 +            }
 +            let (cast_from, cast_to) = (
 +                cx.typeck_results().expr_ty(cast_expr),
 +                cx.typeck_results().expr_ty(expr),
 +            );
 +
 +            if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
 +                return;
 +            }
 +
 +            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +
 +            if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
 +                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +                if cast_from.is_numeric() {
 +                    cast_possible_wrap::check(cx, expr, cast_from, cast_to);
 +                    cast_precision_loss::check(cx, expr, cast_from, cast_to);
 +                    cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
++                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
 +                }
 +                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
 +                cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
 +            }
 +        }
 +
 +        cast_ref_to_mut::check(cx, expr);
 +        cast_ptr_alignment::check(cx, expr);
 +        char_lit_as_u8::check(cx, expr);
 +        ptr_as_ptr::check(cx, expr, &self.msrv);
 +        cast_slice_different_sizes::check(cx, expr, &self.msrv);
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
index 470c8c7ea26a60dd2b48b142ffac3cb6ec10a63b,0000000000000000000000000000000000000000..af56ec11ef8acd741ec4a8a45926d8fd2656e36a
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,126 @@@
- use rustc_hir::{Expr, ExprKind, Lit, UnOp};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::numeric_literal::NumericLiteral;
 +use clippy_utils::source::snippet_opt;
 +use if_chain::if_chain;
 +use rustc_ast::{LitFloatType, LitIntType, LitKind};
 +use rustc_errors::Applicability;
++use rustc_hir::def::Res;
++use rustc_hir::{Expr, ExprKind, Lit, QPath, TyKind, UnOp};
 +use rustc_lint::{LateContext, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
 +
 +use super::UNNECESSARY_CAST;
 +
 +pub(super) fn check(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    cast_expr: &Expr<'_>,
 +    cast_from: Ty<'_>,
 +    cast_to: Ty<'_>,
 +) -> bool {
++    // skip non-primitive type cast
++    if_chain! {
++        if let ExprKind::Cast(_, cast_to) = expr.kind;
++        if let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind;
++        if let Res::PrimTy(_) = path.res;
++        then {}
++        else {
++            return false
++        }
++    }
++
 +    if let Some(lit) = get_numeric_literal(cast_expr) {
 +        let literal_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
 +
 +        if_chain! {
 +            if let LitKind::Int(n, _) = lit.node;
 +            if let Some(src) = snippet_opt(cx, cast_expr.span);
 +            if cast_to.is_floating_point();
 +            if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
 +            let from_nbits = 128 - n.leading_zeros();
 +            let to_nbits = fp_ty_mantissa_nbits(cast_to);
 +            if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
 +            then {
 +                lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
 +                return true
 +            }
 +        }
 +
 +        match lit.node {
 +            LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
 +                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
 +            },
 +            LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
 +                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
 +            },
 +            LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
 +            LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_))
 +            | LitKind::Float(_, LitFloatType::Suffixed(_))
 +                if cast_from.kind() == cast_to.kind() =>
 +            {
 +                if let Some(src) = snippet_opt(cx, cast_expr.span) {
 +                    if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
 +                        lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
 +                    }
 +                }
 +            },
 +            _ => {
 +                if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        UNNECESSARY_CAST,
 +                        expr.span,
 +                        &format!(
 +                            "casting to the same type is unnecessary (`{}` -> `{}`)",
 +                            cast_from, cast_to
 +                        ),
 +                        "try",
 +                        literal_str,
 +                        Applicability::MachineApplicable,
 +                    );
 +                    return true;
 +                }
 +            },
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
 +    span_lint_and_sugg(
 +        cx,
 +        UNNECESSARY_CAST,
 +        expr.span,
 +        &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
 +        "try",
 +        format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
 +    match expr.kind {
 +        ExprKind::Lit(ref lit) => Some(lit),
 +        ExprKind::Unary(UnOp::Neg, e) => {
 +            if let ExprKind::Lit(ref lit) = e.kind {
 +                Some(lit)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +/// Returns the mantissa bits wide of a fp type.
 +/// Will return 0 if the type is not a fp
 +fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
 +    match typ.kind() {
 +        ty::Float(FloatTy::F32) => 23,
 +        ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
 +        _ => 0,
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fc141b4a6e3afcc3874b5c776be3cfb88303bdfc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,125 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use rustc_ast::ast::{AttrKind, Attribute, Item, ItemKind};
++use rustc_ast::token::{Token, TokenKind};
++use rustc_ast::tokenstream::{TokenStream, TokenTree};
++use rustc_errors::Applicability;
++use rustc_lint::{EarlyContext, EarlyLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::{symbol::sym, Span};
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for use of `crate` as opposed to `$crate` in a macro definition.
++    ///
++    /// ### Why is this bad?
++    /// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
++    /// crate. Rarely is the former intended. See:
++    /// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
++    ///
++    /// ### Example
++    /// ```rust
++    /// #[macro_export]
++    /// macro_rules! print_message {
++    ///     () => {
++    ///         println!("{}", crate::MESSAGE);
++    ///     };
++    /// }
++    /// pub const MESSAGE: &str = "Hello!";
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// #[macro_export]
++    /// macro_rules! print_message {
++    ///     () => {
++    ///         println!("{}", $crate::MESSAGE);
++    ///     };
++    /// }
++    /// pub const MESSAGE: &str = "Hello!";
++    /// ```
++    ///
++    /// Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
++    /// macro definition, e.g.:
++    /// ```rust,ignore
++    /// #[allow(clippy::crate_in_macro_def)]
++    /// macro_rules! ok { ... crate::foo ... }
++    /// ```
++    #[clippy::version = "1.61.0"]
++    pub CRATE_IN_MACRO_DEF,
++    suspicious,
++    "using `crate` in a macro definition"
++}
++declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]);
++
++impl EarlyLintPass for CrateInMacroDef {
++    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
++        if_chain! {
++            if item.attrs.iter().any(is_macro_export);
++            if let ItemKind::MacroDef(macro_def) = &item.kind;
++            let tts = macro_def.body.inner_tokens();
++            if let Some(span) = contains_unhygienic_crate_reference(&tts);
++            then {
++                span_lint_and_sugg(
++                    cx,
++                    CRATE_IN_MACRO_DEF,
++                    span,
++                    "`crate` references the macro call's crate",
++                    "to reference the macro definition's crate, use",
++                    String::from("$crate"),
++                    Applicability::MachineApplicable,
++                );
++            }
++        }
++    }
++}
++
++fn is_macro_export(attr: &Attribute) -> bool {
++    if_chain! {
++        if let AttrKind::Normal(attr_item, _) = &attr.kind;
++        if let [segment] = attr_item.path.segments.as_slice();
++        then {
++            segment.ident.name == sym::macro_export
++        } else {
++            false
++        }
++    }
++}
++
++fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
++    let mut prev_is_dollar = false;
++    let mut cursor = tts.trees();
++    while let Some(curr) = cursor.next() {
++        if_chain! {
++            if !prev_is_dollar;
++            if let Some(span) = is_crate_keyword(&curr);
++            if let Some(next) = cursor.look_ahead(0);
++            if is_token(next, &TokenKind::ModSep);
++            then {
++                return Some(span);
++            }
++        }
++        if let TokenTree::Delimited(_, _, tts) = &curr {
++            let span = contains_unhygienic_crate_reference(tts);
++            if span.is_some() {
++                return span;
++            }
++        }
++        prev_is_dollar = is_token(&curr, &TokenKind::Dollar);
++    }
++    None
++}
++
++fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
++    if_chain! {
++        if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }) = tt;
++        if symbol.as_str() == "crate";
++        then { Some(*span) } else { None }
++    }
++}
++
++fn is_token(tt: &TokenTree, kind: &TokenKind) -> bool {
++    if let TokenTree::Token(Token { kind: other, .. }) = tt {
++        kind == other
++    } else {
++        false
++    }
++}
index 92cf82bcd6a34bf314df7c35824f6c4e8b7189ff,0000000000000000000000000000000000000000..28d0c75fde6baf95b8d89bc22f973ae928509072
mode 100644,000000..100644
--- /dev/null
@@@ -1,849 -1,0 +1,849 @@@
-                 let fallback_bundle = rustc_errors::fallback_fluent_bundle(false)
-                     .expect("failed to load fallback fluent bundle");
 +use clippy_utils::attrs::is_doc_hidden;
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
 +use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 +use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 +use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 +use if_chain::if_chain;
 +use itertools::Itertools;
 +use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, 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::{Applicability, Handler, MultiSpan, SuggestionStyle};
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{self, Visitor};
 +use rustc_hir::{AnonConst, Expr};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::nested_filter;
 +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, 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. Therefore, 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() {}
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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!();
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    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!();
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.41.0"]
 +    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
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    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!();
 +    /// }
 +    /// ``````
 +    #[clippy::version = "1.40.0"]
 +    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();
 +            },
 +            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
 +    }
 +
 +    // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
 +    if cx
 +        .tcx
 +        .hir()
 +        .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
 +        .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
 +    {
 +        return;
 +    }
 +
 +    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;
 +                }
 +                let trimmed_text = text.trim();
 +                headers.safety |= in_heading && trimmed_text == "Safety";
 +                headers.safety |= in_heading && trimmed_text == "Implementation safety";
 +                headers.safety |= in_heading && trimmed_text == "Implementation Safety";
 +                headers.errors |= in_heading && trimmed_text == "Errors";
 +                headers.panics |= in_heading && trimmed_text == "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 fallback_bundle =
++                    rustc_errors::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
 +                let emitter = EmitterWriter::new(
 +                    Box::new(io::sink()),
 +                    None,
 +                    None,
 +                    fallback_bundle,
 +                    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) => {
 +                        drop(errs);
 +                        return false;
 +                    },
 +                };
 +
 +                let mut relevant_main_found = false;
 +                loop {
 +                    match parser.parse_item(ForceCollect::No) {
 +                        Ok(Some(item)) => match &item.kind {
 +                            ItemKind::Fn(box Fn {
 +                                sig, body: 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;
 +                                }
 +                            },
 +                            // Tests with one of these items are ignored
 +                            ItemKind::Static(..)
 +                            | ItemKind::Const(..)
 +                            | ItemKind::ExternCrate(..)
 +                            | ItemKind::ForeignMod(..)
 +                            // Another function was found; this case is ignored
 +                            | ItemKind::Fn(..) => return false,
 +                            _ => {},
 +                        },
 +                        Ok(None) => break,
 +                        Err(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. Also preserve `::` as a prefix/suffix.
 +        let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
 +
 +        // Remove leading or trailing single `:` which may be part of a sentence.
 +        if word.starts_with(':') && !word.starts_with("::") {
 +            word = word.trim_start_matches(':');
 +        }
 +        if word.ends_with(':') && !word.ends_with("::") {
 +            word = word.trim_end_matches(':');
 +        }
 +
 +        if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
 +            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 backticks. (Issue #2343)
 +    if has_underscore(word) && has_hyphen(word) {
 +        return;
 +    }
 +
 +    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
 +        let mut applicability = Applicability::MachineApplicable;
 +
 +        span_lint_and_then(
 +            cx,
 +            DOC_MARKDOWN,
 +            span,
 +            "item in documentation is missing backticks",
 +            |diag| {
 +                let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
 +                diag.span_suggestion_with_style(
 +                    span,
 +                    "try",
 +                    format!("`{}`", snippet),
 +                    applicability,
 +                    // always show the suggestion in a separate line, since the
 +                    // inline presentation adds another pair of backticks
 +                    SuggestionStyle::ShowAlways,
 +                );
 +            },
 +        );
 +    }
 +}
 +
 +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 NestedFilter = nested_filter::OnlyBodies;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.panic_span.is_some() {
 +            return;
 +        }
 +
 +        if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) {
 +            if is_panic(self.cx, macro_call.def_id)
 +                || matches!(
 +                    self.cx.tcx.item_name(macro_call.def_id).as_str(),
 +                    "assert" | "assert_eq" | "assert_ne" | "todo"
 +                )
 +            {
 +                self.panic_span = Some(macro_call.span);
 +            }
 +        }
 +
 +        // check for `unwrap`
 +        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
 +            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
 +            if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
 +                || is_type_diagnostic_item(self.cx, receiver_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) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +}
index 5c4b35fd4b9d2e572b155fb29e85b3cf7019ecf3,0000000000000000000000000000000000000000..88c54828da834da3e94ae9d513a76102e1d1f0c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,170 -1,0 +1,243 @@@
- use clippy_utils::diagnostics::span_lint_and_note;
- use clippy_utils::ty::is_copy;
- use if_chain::if_chain;
- use rustc_hir::{Expr, ExprKind};
++use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
++use clippy_utils::is_must_use_func_call;
++use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
++use rustc_hir::{Expr, ExprKind, LangItem};
 +use rustc_lint::{LateContext, LateLintPass};
- use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `std::mem::drop` with a reference
 +    /// instead of an owned value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `drop` on a reference will only drop the
 +    /// reference itself, which is a no-op. It will not call the `drop` method (from
 +    /// the `Drop` trait implementation) on the underlying referenced value, which
 +    /// is likely what was intended.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// let mut lock_guard = mutex.lock();
 +    /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
 +    /// // still locked
 +    /// operation_that_requires_mutex_to_be_unlocked();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DROP_REF,
 +    correctness,
 +    "calls to `std::mem::drop` with a reference instead of an owned value"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `std::mem::forget` with a reference
 +    /// instead of an owned value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `forget` on a reference will only forget the
 +    /// reference itself, which is a no-op. It will not forget the underlying
 +    /// referenced
 +    /// value, which is likely what was intended.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = Box::new(1);
 +    /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FORGET_REF,
 +    correctness,
 +    "calls to `std::mem::forget` with a reference instead of an owned value"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `std::mem::drop` with a value
 +    /// that derives the Copy trait
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `std::mem::drop` [does nothing for types that
 +    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
 +    /// value will be copied and moved into the function on invocation.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: i32 = 42; // i32 implements Copy
 +    /// std::mem::drop(x) // A copy of x is passed to the function, leaving the
 +    ///                   // original unaffected
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub DROP_COPY,
 +    correctness,
 +    "calls to `std::mem::drop` with a value that implements Copy"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `std::mem::forget` with a value that
 +    /// derives the Copy trait
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling `std::mem::forget` [does nothing for types that
 +    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
 +    /// value will be copied and moved into the function on invocation.
 +    ///
 +    /// An alternative, but also valid, explanation is that Copy types do not
 +    /// implement
 +    /// the Drop trait, which means they have no destructors. Without a destructor,
 +    /// there
 +    /// is nothing for `std::mem::forget` to ignore.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: i32 = 42; // i32 implements Copy
 +    /// std::mem::forget(x) // A copy of x is passed to the function, leaving the
 +    ///                     // original unaffected
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FORGET_COPY,
 +    correctness,
 +    "calls to `std::mem::forget` with a value that implements Copy"
 +}
 +
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
++    ///
++    /// ### Why is this bad?
++    /// Calling `std::mem::drop` is no different than dropping such a type. A different value may
++    /// have been intended.
++    ///
++    /// ### Example
++    /// ```rust
++    /// struct Foo;
++    /// let x = Foo;
++    /// std::mem::drop(x);
++    /// ```
++    #[clippy::version = "1.61.0"]
++    pub DROP_NON_DROP,
++    suspicious,
++    "call to `std::mem::drop` with a value which does not implement `Drop`"
++}
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
++    ///
++    /// ### Why is this bad?
++    /// Calling `std::mem::forget` is no different than dropping such a type. A different value may
++    /// have been intended.
++    ///
++    /// ### Example
++    /// ```rust
++    /// struct Foo;
++    /// let x = Foo;
++    /// std::mem::forget(x);
++    /// ```
++    #[clippy::version = "1.61.0"]
++    pub FORGET_NON_DROP,
++    suspicious,
++    "call to `std::mem::forget` with a value which does not implement `Drop`"
++}
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
++    ///
++    /// ### Why is this bad?
++    /// The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
++    ///
++    /// ### Known problems
++    /// Does not catch cases if the user binds `std::mem::drop`
++    /// to a different name and calls it that way.
++    ///
++    /// ### Example
++    /// ```rust
++    /// struct S;
++    /// drop(std::mem::ManuallyDrop::new(S));
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// struct S;
++    /// unsafe {
++    ///     std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
++    /// }
++    /// ```
++    #[clippy::version = "1.49.0"]
++    pub UNDROPPED_MANUALLY_DROPS,
++    correctness,
++    "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
++}
++
 +const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \
 +                                Dropping a reference does nothing";
 +const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \
 +                                  Forgetting a reference does nothing";
 +const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \
 +                                 Dropping a copy leaves the original intact";
 +const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
 +                                   Forgetting a copy leaves the original intact";
++const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
++                                 Dropping such a type only extends it's contained lifetimes";
++const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
++                                   Forgetting such a type is the same as dropping it";
 +
- declare_lint_pass!(DropForgetRef => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY]);
++declare_lint_pass!(DropForgetRef => [
++    DROP_REF,
++    FORGET_REF,
++    DROP_COPY,
++    FORGET_COPY,
++    DROP_NON_DROP,
++    FORGET_NON_DROP,
++    UNDROPPED_MANUALLY_DROPS
++]);
 +
 +impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-         if_chain! {
-             if let ExprKind::Call(path, args) = expr.kind;
-             if let ExprKind::Path(ref qpath) = path.kind;
-             if args.len() == 1;
-             if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
-             then {
-                 let lint;
-                 let msg;
-                 let arg = &args[0];
-                 let arg_ty = cx.typeck_results().expr_ty(arg);
-                 if let ty::Ref(..) = arg_ty.kind() {
-                     match cx.tcx.get_diagnostic_name(def_id) {
-                         Some(sym::mem_drop) => {
-                             lint = DROP_REF;
-                             msg = DROP_REF_SUMMARY.to_string();
-                         },
-                         Some(sym::mem_forget) => {
-                             lint = FORGET_REF;
-                             msg = FORGET_REF_SUMMARY.to_string();
-                         },
-                         _ => return,
-                     }
-                     span_lint_and_note(cx,
-                                        lint,
-                                        expr.span,
-                                        &msg,
-                                        Some(arg.span),
-                                        &format!("argument has type `{}`", arg_ty));
-                 } else if is_copy(cx, arg_ty) {
-                     match cx.tcx.get_diagnostic_name(def_id) {
-                         Some(sym::mem_drop) => {
-                             lint = DROP_COPY;
-                             msg = DROP_COPY_SUMMARY.to_string();
-                         },
-                         Some(sym::mem_forget) => {
-                             lint = FORGET_COPY;
-                             msg = FORGET_COPY_SUMMARY.to_string();
-                         },
-                         _ => return,
-                     }
-                     span_lint_and_note(cx,
-                                        lint,
-                                        expr.span,
-                                        &msg,
-                                        Some(arg.span),
-                                        &format!("argument has type {}", arg_ty));
++        if let ExprKind::Call(path, [arg]) = expr.kind
++            && let ExprKind::Path(ref qpath) = path.kind
++            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
++            && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
++        {
++            let arg_ty = cx.typeck_results().expr_ty(arg);
++            let (lint, msg) = match fn_name {
++                sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
++                sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
++                sym::mem_drop if is_copy(cx, arg_ty) => (DROP_COPY, DROP_COPY_SUMMARY),
++                sym::mem_forget if is_copy(cx, arg_ty) => (FORGET_COPY, FORGET_COPY_SUMMARY),
++                sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
++                    span_lint_and_help(
++                        cx,
++                        UNDROPPED_MANUALLY_DROPS,
++                        expr.span,
++                        "the inner value of this ManuallyDrop will not be dropped",
++                        None,
++                        "to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop",
++                    );
++                    return;
 +                }
-             }
++                sym::mem_drop
++                    if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
++                        || is_must_use_func_call(cx, arg)
++                        || is_must_use_ty(cx, arg_ty)) =>
++                {
++                    (DROP_NON_DROP, DROP_NON_DROP_SUMMARY)
++                },
++                sym::mem_forget if !arg_ty.needs_drop(cx.tcx, cx.param_env) => {
++                    (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY)
++                },
++                _ => return,
++            };
++            span_lint_and_note(
++                cx,
++                lint,
++                expr.span,
++                msg,
++                Some(arg.span),
++                &format!("argument has type `{}`", arg_ty),
++            );
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fdeac8d82557fd518cb54143fe152246070bd2bb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,99 @@@
++use clippy_utils::{diagnostics::span_lint_and_then, source::snippet_opt};
++use rustc_ast::ast::{Item, ItemKind, VariantData};
++use rustc_errors::Applicability;
++use rustc_lexer::TokenKind;
++use rustc_lint::{EarlyContext, EarlyLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::Span;
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Finds structs without fields (a so-called "empty struct") that are declared with brackets.
++    ///
++    /// ### Why is this bad?
++    /// Empty brackets after a struct declaration can be omitted.
++    ///
++    /// ### Example
++    /// ```rust
++    /// struct Cookie {}
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// struct Cookie;
++    /// ```
++    #[clippy::version = "1.62.0"]
++    pub EMPTY_STRUCTS_WITH_BRACKETS,
++    restriction,
++    "finds struct declarations with empty brackets"
++}
++declare_lint_pass!(EmptyStructsWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS]);
++
++impl EarlyLintPass for EmptyStructsWithBrackets {
++    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
++        let span_after_ident = item.span.with_lo(item.ident.span.hi());
++
++        if let ItemKind::Struct(var_data, _) = &item.kind
++            && has_brackets(var_data)
++            && has_no_fields(cx, var_data, span_after_ident) {
++            span_lint_and_then(
++                cx,
++                EMPTY_STRUCTS_WITH_BRACKETS,
++                span_after_ident,
++                "found empty brackets on struct declaration",
++                |diagnostic| {
++                    diagnostic.span_suggestion_hidden(
++                        span_after_ident,
++                        "remove the brackets",
++                        ";".to_string(),
++                        Applicability::MachineApplicable);
++                    },
++            );
++        }
++    }
++}
++
++fn has_no_ident_token(braces_span_str: &str) -> bool {
++    !rustc_lexer::tokenize(braces_span_str).any(|t| t.kind == TokenKind::Ident)
++}
++
++fn has_brackets(var_data: &VariantData) -> bool {
++    !matches!(var_data, VariantData::Unit(_))
++}
++
++fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Span) -> bool {
++    if !var_data.fields().is_empty() {
++        return false;
++    }
++
++    // there might still be field declarations hidden from the AST
++    // (conditionaly compiled code using #[cfg(..)])
++
++    let Some(braces_span_str) = snippet_opt(cx, braces_span) else {
++        return false;
++    };
++
++    has_no_ident_token(braces_span_str.as_ref())
++}
++
++#[cfg(test)]
++mod unit_test {
++    use super::*;
++
++    #[test]
++    fn test_has_no_ident_token() {
++        let input = "{ field: u8 }";
++        assert!(!has_no_ident_token(input));
++
++        let input = "(u8, String);";
++        assert!(!has_no_ident_token(input));
++
++        let input = " {
++                // test = 5
++        }
++        ";
++        assert!(has_no_ident_token(input));
++
++        let input = " ();";
++        assert!(has_no_ident_token(input));
++    }
++}
index f824f20ca40a017b28d725fcc452fc50f3209e55,0000000000000000000000000000000000000000..4d6bef89bea7f09cbbfa8f618b4d26b871e371b6
mode 100644,000000..100644
--- /dev/null
@@@ -1,97 -1,0 +1,114 @@@
- use clippy_utils::consts::{constant_simple, Constant};
 +use clippy_utils::source::snippet;
 +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
-             span_lint(
-                 cx,
-                 IDENTITY_OP,
-                 span,
-                 &format!(
-                     "the operation is ineffective. Consider reducing it to `{}`",
-                     snippet(cx, arg, "..")
-                 ),
-             );
++use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::{clip, unsext};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for identity operations, e.g., `x + 0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This code can be removed without changing the
 +    /// meaning. So it just obscures what's going on. Delete it mercilessly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// x / 1 + 0 * 1 - 0 | 0;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub IDENTITY_OP,
 +    complexity,
 +    "using identity operations, e.g., `x + 0` or `y / 1`"
 +}
 +
 +declare_lint_pass!(IdentityOp => [IDENTITY_OP]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IdentityOp {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::Binary(cmp, left, right) = e.kind {
 +            if is_allowed(cx, cmp, left, right) {
 +                return;
 +            }
 +            match cmp.node {
 +                BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
 +                    check(cx, left, 0, e.span, right.span);
 +                    check(cx, right, 0, e.span, left.span);
 +                },
 +                BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
 +                BinOpKind::Mul => {
 +                    check(cx, left, 1, e.span, right.span);
 +                    check(cx, right, 1, e.span, left.span);
 +                },
 +                BinOpKind::Div => check(cx, right, 1, e.span, left.span),
 +                BinOpKind::BitAnd => {
 +                    check(cx, left, -1, e.span, right.span);
 +                    check(cx, right, -1, e.span, left.span);
 +                },
++                BinOpKind::Rem => check_remainder(cx, left, right, e.span, left.span),
 +                _ => (),
 +            }
 +        }
 +    }
 +}
 +
 +fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
 +    // This lint applies to integers
 +    !cx.typeck_results().expr_ty(left).peel_refs().is_integral()
 +        || !cx.typeck_results().expr_ty(right).peel_refs().is_integral()
 +        // `1 << 0` is a common pattern in bit manipulation code
 +        || (cmp.node == BinOpKind::Shl
 +            && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
 +            && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
 +}
 +
++fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
++    let lhs_const = constant_full_int(cx, cx.typeck_results(), left);
++    let rhs_const = constant_full_int(cx, cx.typeck_results(), right);
++    if match (lhs_const, rhs_const) {
++        (Some(FullInt::S(lv)), Some(FullInt::S(rv))) => lv.abs() < rv.abs(),
++        (Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
++        _ => return,
++    } {
++        span_ineffective_operation(cx, span, arg);
++    }
++}
++
 +fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
 +    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
 +        let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
 +            ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
 +            ty::Uint(uty) => clip(cx.tcx, !0, uty),
 +            _ => return,
 +        };
 +        if match m {
 +            0 => v == 0,
 +            -1 => v == check,
 +            1 => v == 1,
 +            _ => unreachable!(),
 +        } {
++            span_ineffective_operation(cx, span, arg);
 +        }
 +    }
 +}
++
++fn span_ineffective_operation(cx: &LateContext<'_>, span: Span, arg: Span) {
++    span_lint(
++        cx,
++        IDENTITY_OP,
++        span,
++        &format!(
++            "the operation is ineffective. Consider reducing it to `{}`",
++            snippet(cx, arg, "..")
++        ),
++    );
++}
index 9ead4bb27a5881eb3ab43d6def4481f658999b44,0000000000000000000000000000000000000000..4ba7477add82a420dc3b160da1782e880adf85a0
mode 100644,000000..100644
--- /dev/null
@@@ -1,206 -1,0 +1,214 @@@
 +//! lint on indexing and slicing operations
 +
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::higher;
 +use rustc_ast::ast::RangeLimits;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for out of bounds array indexing with a constant
 +    /// index.
 +    ///
 +    /// ### Why is this bad?
 +    /// This will always panic at runtime.
 +    ///
 +    /// ### Known problems
 +    /// Hopefully none.
 +    ///
 +    /// ### Example
 +    /// ```no_run
 +    /// # #![allow(const_err)]
 +    /// let x = [1, 2, 3, 4];
 +    ///
 +    /// // Bad
 +    /// x[9];
 +    /// &x[2..9];
 +    ///
 +    /// // Good
 +    /// x[0];
 +    /// x[3];
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OUT_OF_BOUNDS_INDEXING,
 +    correctness,
 +    "out of bounds constant indexing"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of indexing or slicing. Arrays are special cases, this lint
 +    /// does report on arrays if we can tell that slicing operations are in bounds and does not
 +    /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
 +    ///
 +    /// ### Why is this bad?
 +    /// Indexing and slicing can panic at runtime and there are
 +    /// safe alternatives.
 +    ///
 +    /// ### Known problems
 +    /// Hopefully none.
 +    ///
 +    /// ### Example
 +    /// ```rust,no_run
 +    /// // Vector
 +    /// let x = vec![0; 5];
 +    ///
 +    /// // Bad
 +    /// x[2];
 +    /// &x[2..100];
 +    /// &x[2..];
 +    /// &x[..100];
 +    ///
 +    /// // Good
 +    /// x.get(2);
 +    /// x.get(2..100);
 +    /// x.get(2..);
 +    /// x.get(..100);
 +    ///
 +    /// // Array
 +    /// let y = [0, 1, 2, 3];
 +    ///
 +    /// // Bad
 +    /// &y[10..100];
 +    /// &y[10..];
 +    /// &y[..100];
 +    ///
 +    /// // Good
 +    /// &y[2..];
 +    /// &y[..2];
 +    /// &y[0..3];
 +    /// y.get(10);
 +    /// y.get(10..100);
 +    /// y.get(10..);
 +    /// y.get(..100);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub INDEXING_SLICING,
 +    restriction,
 +    "indexing/slicing usage"
 +}
 +
 +declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
++        if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
++            return;
++        }
++
 +        if let ExprKind::Index(array, index) = &expr.kind {
 +            let ty = cx.typeck_results().expr_ty(array).peel_refs();
 +            if let Some(range) = higher::Range::hir(index) {
 +                // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
 +                if let ty::Array(_, s) = ty.kind() {
 +                    let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
 +                        size.into()
 +                    } else {
 +                        return;
 +                    };
 +
 +                    let const_range = to_const_range(cx, range, size);
 +
 +                    if let (Some(start), _) = const_range {
 +                        if start > size {
 +                            span_lint(
 +                                cx,
 +                                OUT_OF_BOUNDS_INDEXING,
 +                                range.start.map_or(expr.span, |start| start.span),
 +                                "range is out of bounds",
 +                            );
 +                            return;
 +                        }
 +                    }
 +
 +                    if let (_, Some(end)) = const_range {
 +                        if end > size {
 +                            span_lint(
 +                                cx,
 +                                OUT_OF_BOUNDS_INDEXING,
 +                                range.end.map_or(expr.span, |end| end.span),
 +                                "range is out of bounds",
 +                            );
 +                            return;
 +                        }
 +                    }
 +
 +                    if let (Some(_), Some(_)) = const_range {
 +                        // early return because both start and end are constants
 +                        // and we have proven above that they are in bounds
 +                        return;
 +                    }
 +                }
 +
 +                let help_msg = match (range.start, range.end) {
 +                    (None, Some(_)) => "consider using `.get(..n)`or `.get_mut(..n)` instead",
 +                    (Some(_), None) => "consider using `.get(n..)` or .get_mut(n..)` instead",
 +                    (Some(_), Some(_)) => "consider using `.get(n..m)` or `.get_mut(n..m)` instead",
 +                    (None, None) => return, // [..] is ok.
 +                };
 +
 +                span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
 +            } else {
 +                // Catchall non-range index, i.e., [n] or [n << m]
 +                if let ty::Array(..) = ty.kind() {
++                    // Index is a const block.
++                    if let ExprKind::ConstBlock(..) = index.kind {
++                        return;
++                    }
 +                    // Index is a constant uint.
 +                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
 +                        // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
 +                        return;
 +                    }
 +                }
 +
 +                span_lint_and_help(
 +                    cx,
 +                    INDEXING_SLICING,
 +                    expr.span,
 +                    "indexing may panic",
 +                    None,
 +                    "consider using `.get(n)` or `.get_mut(n)` instead",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Returns a tuple of options with the start and end (exclusive) values of
 +/// the range. If the start or end is not constant, None is returned.
 +fn to_const_range<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    range: higher::Range<'_>,
 +    array_size: u128,
 +) -> (Option<u128>, Option<u128>) {
 +    let s = range
 +        .start
 +        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
 +    let start = match s {
 +        Some(Some(Constant::Int(x))) => Some(x),
 +        Some(_) => None,
 +        None => Some(0),
 +    };
 +
 +    let e = range
 +        .end
 +        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
 +    let end = match e {
 +        Some(Some(Constant::Int(x))) => {
 +            if range.limits == RangeLimits::Closed {
 +                Some(x + 1)
 +            } else {
 +                Some(x)
 +            }
 +        },
 +        Some(_) => None,
 +        None => Some(array_size),
 +    };
 +
 +    (start, end)
 +}
index 132a466267626e51fd6b0444e0e48763db3880d5,0000000000000000000000000000000000000000..14ca93b5f3c14b3629a0168b421a3527797ffc8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,326 -1,0 +1,331 @@@
-     LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
 +// 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(await_holding_invalid::AWAIT_HOLDING_LOCK),
 +    LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
 +    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_ABS_TO_UNSIGNED),
 +    LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
 +    LintId::of(casts::CAST_ENUM_TRUNCATION),
 +    LintId::of(casts::CAST_REF_TO_MUT),
 +    LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
 +    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(crate_in_macro_def::CRATE_IN_MACRO_DEF),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(dereference::NEEDLESS_BORROW),
 +    LintId::of(derivable_impls::DERIVABLE_IMPLS),
 +    LintId::of(derive::DERIVE_HASH_XOR_EQ),
 +    LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +    LintId::of(disallowed_methods::DISALLOWED_METHODS),
 +    LintId::of(disallowed_types::DISALLOWED_TYPES),
 +    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_NON_DROP),
 +    LintId::of(drop_forget_ref::DROP_REF),
 +    LintId::of(drop_forget_ref::FORGET_COPY),
++    LintId::of(drop_forget_ref::FORGET_NON_DROP),
 +    LintId::of(drop_forget_ref::FORGET_REF),
++    LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(duration_subsec::DURATION_SUBSEC),
 +    LintId::of(entry::MAP_ENTRY),
 +    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::EQ_OP),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(erasing_op::ERASING_OP),
 +    LintId::of(escape::BOXED_LOCAL),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +    LintId::of(explicit_write::EXPLICIT_WRITE),
 +    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(format::USELESS_FORMAT),
 +    LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
 +    LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
 +    LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
 +    LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
 +    LintId::of(formatting::POSSIBLE_MISSING_COMMA),
 +    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(functions::TOO_MANY_ARGUMENTS),
 +    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
 +    LintId::of(identity_op::IDENTITY_OP),
 +    LintId::of(if_let_mutex::IF_LET_MUTEX),
 +    LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +    LintId::of(infinite_iter::INFINITE_ITER),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
 +    LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
 +    LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +    LintId::of(int_plus_one::INT_PLUS_ONE),
 +    LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
 +    LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
 +    LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
 +    LintId::of(lifetimes::NEEDLESS_LIFETIMES),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::EMPTY_LOOP),
 +    LintId::of(loops::EXPLICIT_COUNTER_LOOP),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
 +    LintId::of(loops::ITER_NEXT_LOOP),
 +    LintId::of(loops::MANUAL_FLATTEN),
 +    LintId::of(loops::MANUAL_MEMCPY),
 +    LintId::of(loops::MISSING_SPIN_LOOP),
 +    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_bits::MANUAL_BITS),
 +    LintId::of(manual_map::MANUAL_MAP),
 +    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +    LintId::of(manual_strip::MANUAL_STRIP),
 +    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
 +    LintId::of(map_clone::MAP_CLONE),
 +    LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
 +    LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
 +    LintId::of(match_result_ok::MATCH_RESULT_OK),
 +    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
 +    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +    LintId::of(matches::MATCH_AS_REF),
 +    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
 +    LintId::of(matches::MATCH_OVERLAPPING_ARM),
 +    LintId::of(matches::MATCH_REF_PATS),
 +    LintId::of(matches::MATCH_SINGLE_BINDING),
 +    LintId::of(matches::NEEDLESS_MATCH),
 +    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
 +    LintId::of(matches::SINGLE_MATCH),
 +    LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
 +    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
 +    LintId::of(methods::BIND_INSTEAD_OF_MAP),
 +    LintId::of(methods::BYTES_NTH),
 +    LintId::of(methods::CHARS_LAST_CMP),
 +    LintId::of(methods::CHARS_NEXT_CMP),
 +    LintId::of(methods::CLONE_DOUBLE_REF),
 +    LintId::of(methods::CLONE_ON_COPY),
++    LintId::of(methods::ERR_EXPECT),
 +    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_OVEREAGER_CLONED),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_FILTER_MAP),
 +    LintId::of(methods::MANUAL_FIND_MAP),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MANUAL_SPLIT_ONCE),
 +    LintId::of(methods::MANUAL_STR_REPEAT),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::MAP_FLATTEN),
 +    LintId::of(methods::MAP_IDENTITY),
++    LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
 +    LintId::of(methods::NEEDLESS_SPLITN),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_AS_REF_DEREF),
 +    LintId::of(methods::OPTION_FILTER_MAP),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::OR_FUN_CALL),
 +    LintId::of(methods::OR_THEN_UNWRAP),
 +    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_FIND_MAP),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNNECESSARY_TO_OWNED),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::USELESS_ASREF),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(methods::ZST_OFFSET),
 +    LintId::of(minmax::MIN_MAX),
 +    LintId::of(misc::CMP_NAN),
 +    LintId::of(misc::CMP_OWNED),
 +    LintId::of(misc::MODULO_ONE),
 +    LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
 +    LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
 +    LintId::of(mut_key::MUTABLE_KEY_TYPE),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
 +    LintId::of(needless_bool::BOOL_COMPARISON),
 +    LintId::of(needless_bool::NEEDLESS_BOOL),
 +    LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
 +    LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
-     LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
 +    LintId::of(needless_update::NEEDLESS_UPDATE),
 +    LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(no_effect::NO_EFFECT),
 +    LintId::of(no_effect::UNNECESSARY_OPERATION),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
 +    LintId::of(octal_escapes::OCTAL_ESCAPES),
 +    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
 +    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(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(transmute::CROSSPOINTER_TRANSMUTE),
 +    LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
 +    LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
 +    LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
 +    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
 +    LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
 +    LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +    LintId::of(transmute::WRONG_TRANSMUTE),
 +    LintId::of(transmuting_null::TRANSMUTING_NULL),
 +    LintId::of(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(unicode::INVISIBLE_CHARACTERS),
 +    LintId::of(uninit_vec::UNINIT_VEC),
 +    LintId::of(unit_hash::UNIT_HASH),
 +    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +    LintId::of(unit_types::UNIT_ARG),
 +    LintId::of(unit_types::UNIT_CMP),
 +    LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
 +    LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +    LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
 +    LintId::of(unused_unit::UNUSED_UNIT),
 +    LintId::of(unwrap::PANICKING_UNWRAP),
 +    LintId::of(unwrap::UNNECESSARY_UNWRAP),
 +    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +    LintId::of(useless_conversion::USELESS_CONVERSION),
 +    LintId::of(vec::USELESS_VEC),
 +    LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
 +    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +    LintId::of(write::PRINTLN_EMPTY_STRING),
 +    LintId::of(write::PRINT_LITERAL),
 +    LintId::of(write::PRINT_WITH_NEWLINE),
 +    LintId::of(write::WRITELN_EMPTY_STRING),
 +    LintId::of(write::WRITE_LITERAL),
 +    LintId::of(write::WRITE_WITH_NEWLINE),
 +    LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +])
index a2ce69065f94d47685a1c47f1fa8deb01ecbc05b,0000000000000000000000000000000000000000..10369a855ae6e007f43469e7c58e4f38e4368376
mode 100644,000000..100644
--- /dev/null
@@@ -1,100 -1,0 +1,100 @@@
-     LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
 +// 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::NEEDLESS_MATCH),
 +    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_FLATTEN),
 +    LintId::of(methods::MAP_IDENTITY),
++    LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
 +    LintId::of(methods::NEEDLESS_SPLITN),
 +    LintId::of(methods::OPTION_AS_REF_DEREF),
 +    LintId::of(methods::OPTION_FILTER_MAP),
 +    LintId::of(methods::OR_THEN_UNWRAP),
 +    LintId::of(methods::SEARCH_IS_SOME),
 +    LintId::of(methods::SKIP_WHILE_NEXT),
 +    LintId::of(methods::UNNECESSARY_FILTER_MAP),
 +    LintId::of(methods::UNNECESSARY_FIND_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_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(only_used_in_recursion::ONLY_USED_IN_RECURSION),
 +    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(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_NUM_TO_BYTES),
 +    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 df63f84463dba27345e320748c0b8117dff9d840,0000000000000000000000000000000000000000..6bf2c4bbaedc024ad45ac7970c6fc030be7c9d67
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,76 @@@
-     LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +// 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(casts::CAST_SLICE_DIFFERENT_SIZES),
 +    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(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +    LintId::of(eq_op::EQ_OP),
 +    LintId::of(erasing_op::ERASING_OP),
 +    LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
 +    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(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
 +    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(transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +    LintId::of(transmute::WRONG_TRANSMUTE),
 +    LintId::of(transmuting_null::TRANSMUTING_NULL),
 +    LintId::of(unicode::INVISIBLE_CHARACTERS),
 +    LintId::of(uninit_vec::UNINIT_VEC),
 +    LintId::of(unit_hash::UNIT_HASH),
 +    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +    LintId::of(unit_types::UNIT_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 21f1ef562b5a31482c01c3a56af620d9450e2ad4,0000000000000000000000000000000000000000..532590aaa5a3d294d96dc5cf831318ee8a97c276
mode 100644,000000..100644
--- /dev/null
@@@ -1,552 -1,0 +1,558 @@@
-     needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
 +// 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")]
 +    utils::internal_lints::CLIPPY_LINTS_INTERNAL,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::COMPILER_LINT_FUNCTIONS,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::DEFAULT_LINT,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::IF_CHAIN_STYLE,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::INTERNING_DEFINED_SYMBOL,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::INVALID_PATHS,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::LINT_WITHOUT_LINT_PASS,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::MISSING_MSRV_ATTR_IMPL,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::OUTER_EXPN_EXPN_DATA,
 +    #[cfg(feature = "internal")]
 +    utils::internal_lints::PRODUCE_ICE,
 +    #[cfg(feature = "internal")]
 +    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::ALLOW_ATTRIBUTES_WITHOUT_REASON,
 +    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,
 +    borrow_as_ptr::BORROW_AS_PTR,
 +    bytecount::NAIVE_BYTECOUNT,
 +    cargo::CARGO_COMMON_METADATA,
 +    cargo::MULTIPLE_CRATE_VERSIONS,
 +    cargo::NEGATIVE_FEATURE_NAMES,
 +    cargo::REDUNDANT_FEATURE_NAMES,
 +    cargo::WILDCARD_DEPENDENCIES,
 +    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
++    casts::CAST_ABS_TO_UNSIGNED,
 +    casts::CAST_ENUM_CONSTRUCTOR,
 +    casts::CAST_ENUM_TRUNCATION,
 +    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::CAST_SLICE_DIFFERENT_SIZES,
 +    casts::CHAR_LIT_AS_U8,
 +    casts::FN_TO_NUMERIC_CAST,
 +    casts::FN_TO_NUMERIC_CAST_ANY,
 +    casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    casts::PTR_AS_PTR,
 +    casts::UNNECESSARY_CAST,
 +    checked_conversions::CHECKED_CONVERSIONS,
 +    cognitive_complexity::COGNITIVE_COMPLEXITY,
 +    collapsible_if::COLLAPSIBLE_ELSE_IF,
 +    collapsible_if::COLLAPSIBLE_IF,
 +    collapsible_match::COLLAPSIBLE_MATCH,
 +    comparison_chain::COMPARISON_CHAIN,
 +    copies::BRANCHES_SHARING_CODE,
 +    copies::IFS_SAME_COND,
 +    copies::IF_SAME_THEN_ELSE,
 +    copies::SAME_FUNCTIONS_IN_IF_CONDITION,
 +    copy_iterator::COPY_ITERATOR,
++    crate_in_macro_def::CRATE_IN_MACRO_DEF,
 +    create_dir::CREATE_DIR,
 +    dbg_macro::DBG_MACRO,
 +    default::DEFAULT_TRAIT_ACCESS,
 +    default::FIELD_REASSIGN_WITH_DEFAULT,
 +    default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
 +    default_union_representation::DEFAULT_UNION_REPRESENTATION,
 +    dereference::EXPLICIT_DEREF_METHODS,
 +    dereference::NEEDLESS_BORROW,
 +    dereference::REF_BINDING_TO_REFERENCE,
 +    derivable_impls::DERIVABLE_IMPLS,
 +    derive::DERIVE_HASH_XOR_EQ,
 +    derive::DERIVE_ORD_XOR_PARTIAL_ORD,
 +    derive::EXPL_IMPL_CLONE_ON_COPY,
 +    derive::UNSAFE_DERIVE_DESERIALIZE,
 +    disallowed_methods::DISALLOWED_METHODS,
 +    disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
 +    disallowed_types::DISALLOWED_TYPES,
 +    doc::DOC_MARKDOWN,
 +    doc::MISSING_ERRORS_DOC,
 +    doc::MISSING_PANICS_DOC,
 +    doc::MISSING_SAFETY_DOC,
 +    doc::NEEDLESS_DOCTEST_MAIN,
 +    double_comparison::DOUBLE_COMPARISONS,
 +    double_parens::DOUBLE_PARENS,
 +    drop_forget_ref::DROP_COPY,
++    drop_forget_ref::DROP_NON_DROP,
 +    drop_forget_ref::DROP_REF,
 +    drop_forget_ref::FORGET_COPY,
++    drop_forget_ref::FORGET_NON_DROP,
 +    drop_forget_ref::FORGET_REF,
++    drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
 +    duration_subsec::DURATION_SUBSEC,
 +    else_if_without_else::ELSE_IF_WITHOUT_ELSE,
 +    empty_enum::EMPTY_ENUM,
++    empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
 +    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,
 +    float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
 +    float_literal::EXCESSIVE_PRECISION,
 +    float_literal::LOSSY_FLOAT_LITERAL,
 +    floating_point_arithmetic::IMPRECISE_FLOPS,
 +    floating_point_arithmetic::SUBOPTIMAL_FLOPS,
 +    format::USELESS_FORMAT,
 +    format_args::FORMAT_IN_FORMAT_ARGS,
 +    format_args::TO_STRING_IN_FORMAT_ARGS,
 +    format_impl::PRINT_IN_FORMAT_IMPL,
 +    format_impl::RECURSIVE_FORMAT_IMPL,
 +    formatting::POSSIBLE_MISSING_COMMA,
 +    formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
 +    formatting::SUSPICIOUS_ELSE_FORMATTING,
 +    formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
 +    from_over_into::FROM_OVER_INTO,
 +    from_str_radix_10::FROM_STR_RADIX_10,
 +    functions::DOUBLE_MUST_USE,
 +    functions::MUST_USE_CANDIDATE,
 +    functions::MUST_USE_UNIT,
 +    functions::NOT_UNSAFE_PTR_ARG_DEREF,
 +    functions::RESULT_UNIT_ERR,
 +    functions::TOO_MANY_ARGUMENTS,
 +    functions::TOO_MANY_LINES,
 +    future_not_send::FUTURE_NOT_SEND,
 +    get_last_with_len::GET_LAST_WITH_LEN,
 +    identity_op::IDENTITY_OP,
 +    if_let_mutex::IF_LET_MUTEX,
 +    if_not_else::IF_NOT_ELSE,
 +    if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
 +    implicit_hasher::IMPLICIT_HASHER,
 +    implicit_return::IMPLICIT_RETURN,
 +    implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
 +    inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
 +    index_refutable_slice::INDEX_REFUTABLE_SLICE,
 +    indexing_slicing::INDEXING_SLICING,
 +    indexing_slicing::OUT_OF_BOUNDS_INDEXING,
 +    infinite_iter::INFINITE_ITER,
 +    infinite_iter::MAYBE_INFINITE_ITER,
 +    inherent_impl::MULTIPLE_INHERENT_IMPL,
 +    inherent_to_string::INHERENT_TO_STRING,
 +    inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
 +    init_numbered_fields::INIT_NUMBERED_FIELDS,
 +    inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
 +    int_plus_one::INT_PLUS_ONE,
 +    integer_division::INTEGER_DIVISION,
 +    invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
 +    items_after_statements::ITEMS_AFTER_STATEMENTS,
 +    iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
 +    large_const_arrays::LARGE_CONST_ARRAYS,
 +    large_enum_variant::LARGE_ENUM_VARIANT,
 +    large_stack_arrays::LARGE_STACK_ARRAYS,
 +    len_zero::COMPARISON_TO_EMPTY,
 +    len_zero::LEN_WITHOUT_IS_EMPTY,
 +    len_zero::LEN_ZERO,
 +    let_if_seq::USELESS_LET_IF_SEQ,
 +    let_underscore::LET_UNDERSCORE_DROP,
 +    let_underscore::LET_UNDERSCORE_LOCK,
 +    let_underscore::LET_UNDERSCORE_MUST_USE,
 +    lifetimes::EXTRA_UNUSED_LIFETIMES,
 +    lifetimes::NEEDLESS_LIFETIMES,
 +    literal_representation::DECIMAL_LITERAL_REPRESENTATION,
 +    literal_representation::INCONSISTENT_DIGIT_GROUPING,
 +    literal_representation::LARGE_DIGIT_GROUPS,
 +    literal_representation::MISTYPED_LITERAL_SUFFIXES,
 +    literal_representation::UNREADABLE_LITERAL,
 +    literal_representation::UNUSUAL_BYTE_GROUPINGS,
 +    loops::EMPTY_LOOP,
 +    loops::EXPLICIT_COUNTER_LOOP,
 +    loops::EXPLICIT_INTO_ITER_LOOP,
 +    loops::EXPLICIT_ITER_LOOP,
 +    loops::FOR_KV_MAP,
 +    loops::FOR_LOOPS_OVER_FALLIBLES,
 +    loops::ITER_NEXT_LOOP,
 +    loops::MANUAL_FLATTEN,
 +    loops::MANUAL_MEMCPY,
 +    loops::MISSING_SPIN_LOOP,
 +    loops::MUT_RANGE_BOUND,
 +    loops::NEEDLESS_COLLECT,
 +    loops::NEEDLESS_RANGE_LOOP,
 +    loops::NEVER_LOOP,
 +    loops::SAME_ITEM_PUSH,
 +    loops::SINGLE_ELEMENT_LOOP,
 +    loops::WHILE_IMMUTABLE_CONDITION,
 +    loops::WHILE_LET_LOOP,
 +    loops::WHILE_LET_ON_ITERATOR,
 +    macro_use::MACRO_USE_IMPORTS,
 +    main_recursion::MAIN_RECURSION,
 +    manual_assert::MANUAL_ASSERT,
 +    manual_async_fn::MANUAL_ASYNC_FN,
 +    manual_bits::MANUAL_BITS,
 +    manual_map::MANUAL_MAP,
 +    manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
 +    manual_ok_or::MANUAL_OK_OR,
 +    manual_strip::MANUAL_STRIP,
 +    manual_unwrap_or::MANUAL_UNWRAP_OR,
 +    map_clone::MAP_CLONE,
 +    map_err_ignore::MAP_ERR_IGNORE,
 +    map_unit_fn::OPTION_MAP_UNIT_FN,
 +    map_unit_fn::RESULT_MAP_UNIT_FN,
 +    match_on_vec_items::MATCH_ON_VEC_ITEMS,
 +    match_result_ok::MATCH_RESULT_OK,
 +    match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
 +    matches::INFALLIBLE_DESTRUCTURING_MATCH,
 +    matches::MATCH_AS_REF,
 +    matches::MATCH_BOOL,
 +    matches::MATCH_LIKE_MATCHES_MACRO,
 +    matches::MATCH_OVERLAPPING_ARM,
 +    matches::MATCH_REF_PATS,
 +    matches::MATCH_SAME_ARMS,
 +    matches::MATCH_SINGLE_BINDING,
 +    matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    matches::MATCH_WILD_ERR_ARM,
 +    matches::NEEDLESS_MATCH,
 +    matches::REDUNDANT_PATTERN_MATCHING,
 +    matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    matches::SINGLE_MATCH,
 +    matches::SINGLE_MATCH_ELSE,
 +    matches::WILDCARD_ENUM_MATCH_ARM,
 +    matches::WILDCARD_IN_OR_PATTERNS,
 +    mem_forget::MEM_FORGET,
 +    mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
 +    mem_replace::MEM_REPLACE_WITH_DEFAULT,
 +    mem_replace::MEM_REPLACE_WITH_UNINIT,
 +    methods::BIND_INSTEAD_OF_MAP,
 +    methods::BYTES_NTH,
 +    methods::CHARS_LAST_CMP,
 +    methods::CHARS_NEXT_CMP,
 +    methods::CLONED_INSTEAD_OF_COPIED,
 +    methods::CLONE_DOUBLE_REF,
 +    methods::CLONE_ON_COPY,
 +    methods::CLONE_ON_REF_PTR,
++    methods::ERR_EXPECT,
 +    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_OVEREAGER_CLONED,
 +    methods::ITER_SKIP_NEXT,
 +    methods::ITER_WITH_DRAIN,
 +    methods::MANUAL_FILTER_MAP,
 +    methods::MANUAL_FIND_MAP,
 +    methods::MANUAL_SATURATING_ARITHMETIC,
 +    methods::MANUAL_SPLIT_ONCE,
 +    methods::MANUAL_STR_REPEAT,
 +    methods::MAP_COLLECT_RESULT_UNIT,
 +    methods::MAP_FLATTEN,
 +    methods::MAP_IDENTITY,
 +    methods::MAP_UNWRAP_OR,
++    methods::NEEDLESS_OPTION_AS_DEREF,
 +    methods::NEEDLESS_SPLITN,
 +    methods::NEW_RET_NO_SELF,
 +    methods::OK_EXPECT,
 +    methods::OPTION_AS_REF_DEREF,
 +    methods::OPTION_FILTER_MAP,
 +    methods::OPTION_MAP_OR_NONE,
 +    methods::OR_FUN_CALL,
 +    methods::OR_THEN_UNWRAP,
 +    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_FIND_MAP,
 +    methods::UNNECESSARY_FOLD,
 +    methods::UNNECESSARY_JOIN,
 +    methods::UNNECESSARY_LAZY_EVALUATIONS,
 +    methods::UNNECESSARY_TO_OWNED,
 +    methods::UNWRAP_OR_ELSE_DEFAULT,
 +    methods::UNWRAP_USED,
 +    methods::USELESS_ASREF,
 +    methods::WRONG_SELF_CONVENTION,
 +    methods::ZST_OFFSET,
 +    minmax::MIN_MAX,
 +    misc::CMP_NAN,
 +    misc::CMP_OWNED,
 +    misc::FLOAT_CMP,
 +    misc::FLOAT_CMP_CONST,
 +    misc::MODULO_ONE,
 +    misc::SHORT_CIRCUIT_STATEMENT,
 +    misc::TOPLEVEL_REF_ARG,
 +    misc::USED_UNDERSCORE_BINDING,
 +    misc::ZERO_PTR,
 +    misc_early::BUILTIN_TYPE_SHADOW,
 +    misc_early::DOUBLE_NEG,
 +    misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
 +    misc_early::MIXED_CASE_HEX_LITERALS,
 +    misc_early::REDUNDANT_PATTERN,
 +    misc_early::SEPARATED_LITERAL_SUFFIX,
 +    misc_early::UNNEEDED_FIELD_PATTERN,
 +    misc_early::UNNEEDED_WILDCARD_PATTERN,
 +    misc_early::UNSEPARATED_LITERAL_SUFFIX,
 +    misc_early::ZERO_PREFIXED_LITERAL,
 +    missing_const_for_fn::MISSING_CONST_FOR_FN,
 +    missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
 +    missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
 +    missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
 +    module_style::MOD_MODULE_FILES,
 +    module_style::SELF_NAMED_MODULE_FILES,
 +    modulo_arithmetic::MODULO_ARITHMETIC,
 +    mut_key::MUTABLE_KEY_TYPE,
 +    mut_mut::MUT_MUT,
 +    mut_mutex_lock::MUT_MUTEX_LOCK,
 +    mut_reference::UNNECESSARY_MUT_PASSED,
 +    mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
 +    mutex_atomic::MUTEX_ATOMIC,
 +    mutex_atomic::MUTEX_INTEGER,
 +    needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
 +    needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
 +    needless_bool::BOOL_COMPARISON,
 +    needless_bool::NEEDLESS_BOOL,
 +    needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
 +    needless_continue::NEEDLESS_CONTINUE,
 +    needless_for_each::NEEDLESS_FOR_EACH,
 +    needless_late_init::NEEDLESS_LATE_INIT,
-     undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
 +    needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
 +    needless_question_mark::NEEDLESS_QUESTION_MARK,
 +    needless_update::NEEDLESS_UPDATE,
 +    neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
 +    neg_multiply::NEG_MULTIPLY,
 +    new_without_default::NEW_WITHOUT_DEFAULT,
 +    no_effect::NO_EFFECT,
 +    no_effect::NO_EFFECT_UNDERSCORE_BINDING,
 +    no_effect::UNNECESSARY_OPERATION,
 +    non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
 +    non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
 +    non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
 +    non_expressive_names::MANY_SINGLE_CHAR_NAMES,
 +    non_expressive_names::SIMILAR_NAMES,
 +    non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
 +    non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
 +    nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
 +    octal_escapes::OCTAL_ESCAPES,
 +    only_used_in_recursion::ONLY_USED_IN_RECURSION,
 +    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::DEREF_BY_SLICING,
 +    redundant_slicing::REDUNDANT_SLICING,
 +    redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
 +    ref_option_ref::REF_OPTION_REF,
 +    reference::DEREF_ADDROF,
 +    regex::INVALID_REGEX,
 +    regex::TRIVIAL_REGEX,
 +    repeat_once::REPEAT_ONCE,
 +    return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
 +    returns::LET_AND_RETURN,
 +    returns::NEEDLESS_RETURN,
 +    same_name_method::SAME_NAME_METHOD,
 +    self_assignment::SELF_ASSIGNMENT,
 +    self_named_constructors::SELF_NAMED_CONSTRUCTORS,
 +    semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
 +    serde_api::SERDE_API_MISUSE,
 +    shadow::SHADOW_REUSE,
 +    shadow::SHADOW_SAME,
 +    shadow::SHADOW_UNRELATED,
 +    single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
 +    single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
 +    size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
 +    slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
 +    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
 +    strings::STRING_ADD,
 +    strings::STRING_ADD_ASSIGN,
 +    strings::STRING_FROM_UTF8_AS_BYTES,
 +    strings::STRING_LIT_AS_BYTES,
 +    strings::STRING_SLICE,
 +    strings::STRING_TO_STRING,
 +    strings::STR_TO_STRING,
 +    strlen_on_c_strings::STRLEN_ON_C_STRINGS,
 +    suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
 +    suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
 +    suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
 +    swap::ALMOST_SWAPPED,
 +    swap::MANUAL_SWAP,
 +    tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
 +    temporary_assignment::TEMPORARY_ASSIGNMENT,
 +    to_digit_is_some::TO_DIGIT_IS_SOME,
 +    trailing_empty_array::TRAILING_EMPTY_ARRAY,
 +    trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
 +    trait_bounds::TYPE_REPETITION_IN_BOUNDS,
 +    transmute::CROSSPOINTER_TRANSMUTE,
 +    transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    transmute::TRANSMUTE_BYTES_TO_STR,
 +    transmute::TRANSMUTE_FLOAT_TO_INT,
 +    transmute::TRANSMUTE_INT_TO_BOOL,
 +    transmute::TRANSMUTE_INT_TO_CHAR,
 +    transmute::TRANSMUTE_INT_TO_FLOAT,
 +    transmute::TRANSMUTE_NUM_TO_BYTES,
 +    transmute::TRANSMUTE_PTR_TO_PTR,
 +    transmute::TRANSMUTE_PTR_TO_REF,
 +    transmute::TRANSMUTE_UNDEFINED_REPR,
 +    transmute::UNSOUND_COLLECTION_TRANSMUTE,
 +    transmute::USELESS_TRANSMUTE,
 +    transmute::WRONG_TRANSMUTE,
 +    transmuting_null::TRANSMUTING_NULL,
 +    try_err::TRY_ERR,
 +    types::BORROWED_BOX,
 +    types::BOX_COLLECTION,
 +    types::LINKEDLIST,
 +    types::OPTION_OPTION,
 +    types::RC_BUFFER,
 +    types::RC_MUTEX,
 +    types::REDUNDANT_ALLOCATION,
 +    types::TYPE_COMPLEXITY,
 +    types::VEC_BOX,
 +    undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
 +    unicode::INVISIBLE_CHARACTERS,
 +    unicode::NON_ASCII_LITERAL,
 +    unicode::UNICODE_NOT_NFC,
 +    uninit_vec::UNINIT_VEC,
 +    unit_hash::UNIT_HASH,
 +    unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
 +    unit_types::LET_UNIT_VALUE,
 +    unit_types::UNIT_ARG,
 +    unit_types::UNIT_CMP,
 +    unnamed_address::FN_ADDRESS_COMPARISONS,
 +    unnamed_address::VTABLE_ADDRESS_COMPARISONS,
 +    unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
 +    unnecessary_sort_by::UNNECESSARY_SORT_BY,
 +    unnecessary_wraps::UNNECESSARY_WRAPS,
 +    unnested_or_patterns::UNNESTED_OR_PATTERNS,
 +    unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
 +    unused_async::UNUSED_ASYNC,
 +    unused_io_amount::UNUSED_IO_AMOUNT,
 +    unused_self::UNUSED_SELF,
 +    unused_unit::UNUSED_UNIT,
 +    unwrap::PANICKING_UNWRAP,
 +    unwrap::UNNECESSARY_UNWRAP,
 +    unwrap_in_result::UNWRAP_IN_RESULT,
 +    upper_case_acronyms::UPPER_CASE_ACRONYMS,
 +    use_self::USE_SELF,
 +    useless_conversion::USELESS_CONVERSION,
 +    vec::USELESS_VEC,
 +    vec_init_then_push::VEC_INIT_THEN_PUSH,
 +    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
 +    verbose_file_reads::VERBOSE_FILE_READS,
 +    wildcard_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 6ab139b2fb67b551a80d88a6cf17638111539f01,0000000000000000000000000000000000000000..4802dd877e99d12d90d85d124d164d034bad14ef
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,77 @@@
 +// 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(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
 +    LintId::of(create_dir::CREATE_DIR),
 +    LintId::of(dbg_macro::DBG_MACRO),
 +    LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
 +    LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
 +    LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
 +    LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
++    LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
 +    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::SEPARATED_LITERAL_SUFFIX),
 +    LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
 +    LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
 +    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(redundant_slicing::DEREF_BY_SLICING),
 +    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(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
 +    LintId::of(strings::STRING_ADD),
 +    LintId::of(strings::STRING_SLICE),
 +    LintId::of(strings::STRING_TO_STRING),
 +    LintId::of(strings::STR_TO_STRING),
 +    LintId::of(try_err::TRY_ERR),
 +    LintId::of(types::RC_BUFFER),
 +    LintId::of(types::RC_MUTEX),
 +    LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
 +    LintId::of(unicode::NON_ASCII_LITERAL),
 +    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 dcf399cf9562f3d7c814b8b04b75b2299d336fab,0000000000000000000000000000000000000000..3114afac8863e69f574e172383fcc8f50414f50b
mode 100644,000000..100644
--- /dev/null
@@@ -1,117 -1,0 +1,118 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::style", Some("clippy_style"), vec![
 +    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
 +    LintId::of(blacklisted_name::BLACKLISTED_NAME),
 +    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
 +    LintId::of(collapsible_if::COLLAPSIBLE_IF),
 +    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
 +    LintId::of(comparison_chain::COMPARISON_CHAIN),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(dereference::NEEDLESS_BORROW),
 +    LintId::of(disallowed_methods::DISALLOWED_METHODS),
 +    LintId::of(disallowed_types::DISALLOWED_TYPES),
 +    LintId::of(doc::MISSING_SAFETY_DOC),
 +    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
 +    LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::NEEDLESS_RANGE_LOOP),
 +    LintId::of(loops::SAME_ITEM_PUSH),
 +    LintId::of(loops::WHILE_LET_ON_ITERATOR),
 +    LintId::of(main_recursion::MAIN_RECURSION),
 +    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
 +    LintId::of(manual_bits::MANUAL_BITS),
 +    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::ERR_EXPECT),
 +    LintId::of(methods::INTO_ITER_ON_REF),
 +    LintId::of(methods::ITER_CLONED_COLLECT),
 +    LintId::of(methods::ITER_NEXT_SLICE),
 +    LintId::of(methods::ITER_NTH_ZERO),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
 +    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
 +    LintId::of(methods::SINGLE_CHAR_ADD_STR),
 +    LintId::of(methods::STRING_EXTEND_CHARS),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(ptr::CMP_NULL),
 +    LintId::of(ptr::PTR_ARG),
 +    LintId::of(ptr_eq::PTR_EQ),
 +    LintId::of(question_mark::QUESTION_MARK),
 +    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
 +    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
 +    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +    LintId::of(returns::LET_AND_RETURN),
 +    LintId::of(returns::NEEDLESS_RETURN),
 +    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
 +    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
 +    LintId::of(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 fa3a88e1368ce5cde3ff9aee911e993d4231c604,0000000000000000000000000000000000000000..82f45b5fd58b9691e7c13360c9fe5821de283f4d
mode 100644,000000..100644
--- /dev/null
@@@ -1,26 -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::suspicious", Some("clippy_suspicious"), vec![
 +    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
 +    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +    LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
 +    LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
++    LintId::of(casts::CAST_ABS_TO_UNSIGNED),
 +    LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
 +    LintId::of(casts::CAST_ENUM_TRUNCATION),
++    LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
++    LintId::of(drop_forget_ref::DROP_NON_DROP),
++    LintId::of(drop_forget_ref::FORGET_NON_DROP),
 +    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +    LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
 +    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(octal_escapes::OCTAL_ESCAPES),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +])
index f2a07999144482e48231ba3e4bf19edbf4d71d77,0000000000000000000000000000000000000000..c9b836f95808a623d02b567e5b5ca2f502aa8e33
mode 100644,000000..100644
--- /dev/null
@@@ -1,965 -1,0 +1,966 @@@
- mod needless_option_as_deref;
 +// error-pattern:cargo-clippy
 +
++#![feature(array_windows)]
 +#![feature(binary_heap_into_iter_sorted)]
 +#![feature(box_patterns)]
 +#![feature(control_flow_enum)]
 +#![feature(drain_filter)]
 +#![feature(iter_intersperse)]
 +#![feature(let_chains)]
 +#![feature(let_else)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![feature(stmt_expr_attributes)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +// Disable this rustc lint for now, as it was also done in rustc
 +#![allow(rustc::potential_query_instability)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_arena;
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +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 = "internal")]
 +mod deprecated_lints;
 +#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod absurd_extreme_comparisons;
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod async_yields_async;
 +mod attrs;
 +mod await_holding_invalid;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod bool_assert_comparison;
 +mod booleans;
 +mod borrow_as_ptr;
 +mod bytecount;
 +mod cargo;
 +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 crate_in_macro_def;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod default_numeric_fallback;
 +mod default_union_representation;
 +mod dereference;
 +mod derivable_impls;
 +mod derive;
 +mod disallowed_methods;
 +mod disallowed_script_idents;
 +mod disallowed_types;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duration_subsec;
 +mod else_if_without_else;
 +mod empty_enum;
++mod empty_structs_with_brackets;
 +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 float_equality_without_abs;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod format_args;
 +mod format_impl;
 +mod formatting;
 +mod from_over_into;
 +mod from_str_radix_10;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_not_else;
 +mod if_then_some_else_none;
 +mod implicit_hasher;
 +mod implicit_return;
 +mod implicit_saturating_sub;
 +mod inconsistent_struct_constructor;
 +mod index_refutable_slice;
 +mod indexing_slicing;
 +mod infinite_iter;
 +mod inherent_impl;
 +mod inherent_to_string;
 +mod init_numbered_fields;
 +mod inline_fn_without_body;
 +mod int_plus_one;
 +mod integer_division;
 +mod invalid_upcast_comparisons;
 +mod items_after_statements;
 +mod iter_not_returning_iterator;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_stack_arrays;
 +mod len_zero;
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
 +mod manual_assert;
 +mod manual_async_fn;
 +mod manual_bits;
 +mod manual_map;
 +mod manual_non_exhaustive;
 +mod manual_ok_or;
 +mod manual_strip;
 +mod manual_unwrap_or;
 +mod map_clone;
 +mod map_err_ignore;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod match_result_ok;
 +mod match_str_case_mismatch;
 +mod matches;
 +mod mem_forget;
 +mod mem_replace;
 +mod methods;
 +mod minmax;
 +mod misc;
 +mod misc_early;
 +mod missing_const_for_fn;
 +mod missing_doc;
 +mod missing_enforced_import_rename;
 +mod missing_inline;
 +mod module_style;
 +mod modulo_arithmetic;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_mutex_lock;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bitwise_bool;
 +mod needless_bool;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_for_each;
 +mod needless_late_init;
- mod undropped_manually_drops;
 +mod needless_pass_by_value;
 +mod needless_question_mark;
 +mod needless_update;
 +mod neg_cmp_op_on_partial_ord;
 +mod neg_multiply;
 +mod new_without_default;
 +mod no_effect;
 +mod non_copy_const;
 +mod non_expressive_names;
 +mod non_octal_unix_permissions;
 +mod non_send_fields_in_send_ty;
 +mod nonstandard_macro_braces;
 +mod octal_escapes;
 +mod only_used_in_recursion;
 +mod open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod pass_by_ref_or_value;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_eq;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_else;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_slicing;
 +mod redundant_static_lifetimes;
 +mod ref_option_ref;
 +mod reference;
 +mod regex;
 +mod repeat_once;
 +mod return_self_not_must_use;
 +mod returns;
 +mod same_name_method;
 +mod self_assignment;
 +mod self_named_constructors;
 +mod semicolon_if_nothing_returned;
 +mod serde_api;
 +mod shadow;
 +mod single_char_lifetime_names;
 +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 trailing_empty_array;
 +mod trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod try_err;
 +mod types;
 +mod undocumented_unsafe_blocks;
-     store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref));
 +mod unicode;
 +mod uninit_vec;
 +mod unit_hash;
 +mod unit_return_expecting_ord;
 +mod unit_types;
 +mod unnamed_address;
 +mod unnecessary_self_imports;
 +mod unnecessary_sort_by;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_async;
 +mod unused_io_amount;
 +mod unused_self;
 +mod unused_unit;
 +mod unwrap;
 +mod unwrap_in_result;
 +mod upper_case_acronyms;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_init_then_push;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_imports;
 +mod write;
 +mod zero_div_zero;
 +mod zero_sized_map_values;
 +// end lints modules, do not remove this comment, it’s used in `update_lints`
 +
 +pub use crate::utils::conf::Conf;
 +use crate::utils::conf::TryConf;
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
 +
 +    let msrv = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!(
 +                "error reading Clippy's configuration file. `{}` is not a valid Rust version",
 +                s
 +            ));
 +            None
 +        })
 +    });
 +
 +    store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
 +    store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(sess: &Session) -> Conf {
 +    let file_name = match utils::conf::lookup_conf_file() {
 +        Ok(Some(path)) => path,
 +        Ok(None) => return Conf::default(),
 +        Err(error) => {
 +            sess.struct_err(&format!("error finding Clippy's configuration file: {}", error))
 +                .emit();
 +            return Conf::default();
 +        },
 +    };
 +
 +    let TryConf { conf, errors } = utils::conf::read(&file_name);
 +    // all conf errors are non-fatal, we just use the default conf in case of error
 +    for error in errors {
 +        sess.struct_err(&format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            error
 +        ))
 +        .emit();
 +    }
 +
 +    conf
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
 +    include!("lib.deprecated.rs");
 +
 +    include!("lib.register_lints.rs");
 +    include!("lib.register_restriction.rs");
 +    include!("lib.register_pedantic.rs");
 +
 +    #[cfg(feature = "internal")]
 +    include!("lib.register_internal.rs");
 +
 +    include!("lib.register_all.rs");
 +    include!("lib.register_style.rs");
 +    include!("lib.register_complexity.rs");
 +    include!("lib.register_correctness.rs");
 +    include!("lib.register_suspicious.rs");
 +    include!("lib.register_perf.rs");
 +    include!("lib.register_cargo.rs");
 +    include!("lib.register_nursery.rs");
 +
 +    #[cfg(feature = "internal")]
 +    {
 +        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
 +            store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
 +            return;
 +        }
 +    }
 +
 +    // all the internal lints
 +    #[cfg(feature = "internal")]
 +    {
 +        store.register_early_pass(|| Box::new(utils::internal_lints::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::internal_lints::MsrvAttrImpl));
 +    }
 +
 +    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(undropped_manually_drops::UndroppedManuallyDrops));
 +    store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
 +    store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
 +    store.register_late_pass(|| Box::new(misc::MiscLints));
 +    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
 +    store.register_late_pass(|| Box::new(identity_op::IdentityOp));
 +    store.register_late_pass(|| Box::new(erasing_op::ErasingOp));
 +    store.register_late_pass(|| Box::new(mut_mut::MutMut));
 +    store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed));
 +    store.register_late_pass(|| Box::new(len_zero::LenZero));
 +    store.register_late_pass(|| Box::new(attrs::Attributes));
 +    store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
 +    store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
 +    store.register_late_pass(|| Box::new(unicode::Unicode));
 +    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
 +    store.register_late_pass(|| Box::new(unit_hash::UnitHash));
 +    store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
 +    store.register_late_pass(|| Box::new(strings::StringAdd));
 +    store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
 +    store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
 +    store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback));
 +    store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
 +    store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
 +    store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 +
 +    let msrv = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!(
 +                "error reading Clippy's configuration file. `{}` is not a valid Rust version",
 +                s
 +            ));
 +            None
 +        })
 +    });
 +
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
 +    store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv)));
 +    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
 +    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::new(msrv)));
 +    store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
 +    store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv)));
 +    store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv)));
 +    store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv)));
 +    store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv)));
 +    store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv)));
 +    store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
 +    store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
 +    store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
 +    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
 +    store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv)));
 +
 +    store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
 +    store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
 +    let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
 +    store.register_late_pass(move || {
 +        Box::new(index_refutable_slice::IndexRefutableSlice::new(
 +            max_suggested_slice_pattern_length,
 +            msrv,
 +        ))
 +    });
 +    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
 +    store.register_late_pass(|| Box::new(shadow::Shadow::default()));
 +    store.register_late_pass(|| Box::new(unit_types::UnitTypes));
 +    store.register_late_pass(|| Box::new(loops::Loops));
 +    store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
 +    store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
 +    store.register_late_pass(|| Box::new(entry::HashMapPass));
 +    store.register_late_pass(|| Box::new(minmax::MinMaxPass));
 +    store.register_late_pass(|| Box::new(open_options::OpenOptions));
 +    store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
 +    store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
 +    store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
 +    store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
 +    store.register_late_pass(|| Box::new(no_effect::NoEffect));
 +    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
 +    store.register_late_pass(|| Box::new(transmute::Transmute));
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move || {
 +        Box::new(cognitive_complexity::CognitiveComplexity::new(
 +            cognitive_complexity_threshold,
 +        ))
 +    });
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack }));
 +    store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack }));
 +    store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
 +    store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
 +    store.register_late_pass(|| Box::new(derive::Derive));
 +    store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
 +    store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen));
 +    store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
 +    store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
 +    store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons));
 +    store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
 +    store.register_late_pass(|| Box::new(regex::Regex));
 +    store.register_late_pass(|| Box::new(copies::CopyAndPaste));
 +    store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
 +    store.register_late_pass(|| Box::new(format::UselessFormat));
 +    store.register_late_pass(|| Box::new(swap::Swap));
 +    store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
 +    store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
 +    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || {
 +        Box::new(functions::Functions::new(
 +            too_many_arguments_threshold,
 +            too_many_lines_threshold,
 +        ))
 +    });
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
 +    store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
 +    store.register_late_pass(|| Box::new(mem_forget::MemForget));
 +    store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
 +    store.register_late_pass(|| Box::new(assign_ops::AssignOps));
 +    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
 +    store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence));
 +    store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
 +    store.register_late_pass(|| Box::new(missing_inline::MissingInline));
 +    store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
 +    store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
 +    store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
 +    store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
 +    store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite));
 +    store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue));
 +    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
 +        conf.trivial_copy_size_limit,
 +        conf.pass_by_value_size_limit,
 +        conf.avoid_breaking_exported_api,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move || Box::new(pass_by_ref_or_value));
 +    store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
 +    store.register_late_pass(|| Box::new(try_err::TryErr));
 +    store.register_late_pass(|| Box::new(bytecount::ByteCount));
 +    store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
 +    store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
 +    store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
 +    store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher));
 +    store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom));
 +    store.register_late_pass(|| Box::new(double_comparison::DoubleComparisons));
 +    store.register_late_pass(|| Box::new(question_mark::QuestionMark));
 +    store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
 +    store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl));
 +    store.register_late_pass(|| Box::new(map_unit_fn::MapUnit));
 +    store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
 +    store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
 +    store.register_late_pass(|| Box::new(unwrap::Unwrap));
 +    store.register_late_pass(|| Box::new(duration_subsec::DurationSubsec));
 +    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
 +    store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
 +    store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
 +    store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
 +    store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
 +    store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
 +    store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
 +    store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
 +    store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
 +    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
 +    store.register_late_pass(|| Box::new(integer_division::IntegerDivision));
 +    store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
 +    store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain));
 +    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
 +    store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
 +    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
 +    store.register_early_pass(|| Box::new(double_parens::DoubleParens));
 +    store.register_late_pass(|| Box::new(format_impl::FormatImpl::new()));
 +    store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
 +    store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
 +    store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
 +    store.register_early_pass(|| Box::new(formatting::Formatting));
 +    store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
 +    store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
 +    store.register_late_pass(|| Box::new(returns::Return));
 +    store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
 +    store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
 +    store.register_early_pass(|| Box::new(precedence::Precedence));
 +    store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
 +    store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
 +    store.register_late_pass(|| Box::new(create_dir::CreateDir));
 +    store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
 +    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
 +    store.register_early_pass(move || {
 +        Box::new(literal_representation::LiteralDigitGrouping::new(
 +            literal_representation_lint_fraction_readability,
 +        ))
 +    });
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || {
 +        Box::new(literal_representation::DecimalLiteralRepresentation::new(
 +            literal_representation_threshold,
 +        ))
 +    });
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_late_pass(move || {
 +        Box::new(enum_variants::EnumVariantNames::new(
 +            enum_variant_name_threshold,
 +            avoid_breaking_exported_api,
 +        ))
 +    });
 +    store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
 +    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
 +    store.register_late_pass(move || {
 +        Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
 +            avoid_breaking_exported_api,
 +            upper_case_acronyms_aggressive,
 +        ))
 +    });
 +    store.register_late_pass(|| Box::new(default::Default::default()));
 +    store.register_late_pass(|| Box::new(unused_self::UnusedSelf));
 +    store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
 +    store.register_late_pass(|| Box::new(exit::Exit));
 +    store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome));
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
 +    store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
 +    store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
 +    store.register_early_pass(|| Box::new(as_conversions::AsConversions));
 +    store.register_late_pass(|| Box::new(let_underscore::LetUnderscore));
 +    store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_early_pass(move || {
 +        Box::new(excessive_bools::ExcessiveBools::new(
 +            max_struct_bools,
 +            max_fn_params_bools,
 +        ))
 +    });
 +    store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
 +    store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads));
 +    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
 +    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
 +    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
 +    store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
 +    store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
 +    store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
 +    store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
 +    store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
 +    store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
 +    store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
 +    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
 +    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
 +    store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || {
 +        Box::new(non_expressive_names::NonExpressiveNames {
 +            single_char_binding_names_threshold,
 +        })
 +    });
 +    let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
 +    store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
 +    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
 +    store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
 +    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
 +    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
 +    store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
 +    store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
 +    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
 +    store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
 +    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
 +    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
 +    let disallowed_methods = conf.disallowed_methods.clone();
 +    store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
-     store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
 +    store.register_late_pass(|| Box::new(strings::StrToString));
 +    store.register_late_pass(|| Box::new(strings::StringToString));
 +    store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
 +    store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
 +    store.register_late_pass(|| {
 +        Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons)
 +    });
 +    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
 +    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
 +    store.register_late_pass(|| Box::new(manual_map::ManualMap));
 +    store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
 +    store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
 +    store.register_early_pass(move || Box::new(module_style::ModStyle));
 +    store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
 +    let disallowed_types = conf.disallowed_types.clone();
 +    store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
 +    let import_renames = conf.enforced_import_renames.clone();
 +    store.register_late_pass(move || {
 +        Box::new(missing_enforced_import_rename::ImportRename::new(
 +            import_renames.clone(),
 +        ))
 +    });
 +    let scripts = conf.allowed_scripts.clone();
 +    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
 +    store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
 +    store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
 +    store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
 +    store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
 +    let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
 +    store.register_late_pass(move || {
 +        Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
 +            enable_raw_pointer_heuristic_for_send,
 +        ))
 +    });
++    store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
 +    store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
 +    store.register_late_pass(move || Box::new(format_args::FormatArgs));
 +    store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
 +    store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
 +    store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
 +    store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
 +    store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
 +    store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
 +    store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
 +    store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
 +    store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
 +    store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
 +    store.register_late_pass(|| Box::new(dbg_macro::DbgMacro));
 +    let cargo_ignore_publish = conf.cargo_ignore_publish;
 +    store.register_late_pass(move || {
 +        Box::new(cargo::Cargo {
 +            ignore_publish: cargo_ignore_publish,
 +        })
 +    });
++    store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
++    store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
 +    // add lints here, do not remove this comment, it's used in `new_lint`
 +}
 +
 +#[rustfmt::skip]
 +fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_removed(
 +        "should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "reverse_range_loop",
 +        "this lint is now included in reversed_empty_ranges",
 +    );
 +}
 +
 +/// Register renamed lints.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
 +    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
 +    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
 +    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
 +    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
 +    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
 +    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
 +    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
 +    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
 +    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 +    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 +    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
 +    ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
 +    ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
 +    ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow");
 +    ls.register_renamed("clippy::to_string_in_display", "clippy::recursive_format_impl");
 +
 +    // uplifted lints
 +    ls.register_renamed("clippy::invalid_ref", "invalid_value");
 +    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
 +    ls.register_renamed("clippy::unused_label", "unused_labels");
 +    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
 +    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
 +    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
 +    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
 +    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
 +    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
 +}
 +
 +// only exists to let the dogfood integration test works.
 +// Don't run clippy as an executable directly
 +#[allow(dead_code)]
 +fn main() {
 +    panic!("Please use the cargo-clippy executable");
 +}
index 36ecd83f7d643734e0f0f2df0977cd63f3c5ea70,0000000000000000000000000000000000000000..a0bd7ad0ac647fb7d0f606e932b15a7e5a5031b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,101 @@@
- use rustc_hir::{BorrowKind, Expr, ExprKind, Pat};
 +use super::SINGLE_ELEMENT_LOOP;
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::{indent_of, snippet_with_applicability};
 +use if_chain::if_chain;
++use rustc_ast::util::parser::PREC_PREFIX;
++use rustc_ast::Mutability;
 +use rustc_errors::Applicability;
-     let arg_expr = match arg.kind {
-         ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
-         ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg,
++use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
 +use rustc_lint::LateContext;
++use rustc_span::edition::Edition;
 +
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    pat: &'tcx Pat<'_>,
 +    arg: &'tcx Expr<'_>,
 +    body: &'tcx Expr<'_>,
 +    expr: &'tcx Expr<'_>,
 +) {
-         if let ExprKind::Array([arg_expression]) = arg_expr.kind;
++    let (arg_expression, prefix) = match arg.kind {
++        ExprKind::AddrOf(
++            BorrowKind::Ref,
++            Mutability::Not,
++            Expr {
++                kind: ExprKind::Array([arg]),
++                ..
++            },
++        ) => (arg, "&"),
++        ExprKind::AddrOf(
++            BorrowKind::Ref,
++            Mutability::Mut,
++            Expr {
++                kind: ExprKind::Array([arg]),
++                ..
++            },
++        ) => (arg, "&mut "),
++        ExprKind::MethodCall(
++            method,
++            [
++                Expr {
++                    kind: ExprKind::Array([arg]),
++                    ..
++                },
++            ],
++            _,
++        ) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
++        ExprKind::MethodCall(
++            method,
++            [
++                Expr {
++                    kind: ExprKind::Array([arg]),
++                    ..
++                },
++            ],
++            _,
++        ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
++        ExprKind::MethodCall(
++            method,
++            [
++                Expr {
++                    kind: ExprKind::Array([arg]),
++                    ..
++                },
++            ],
++            _,
++        ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
++        // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
++        ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""),
 +        _ => return,
 +    };
 +    if_chain! {
-             let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
 +        if let ExprKind::Block(block, _) = body.kind;
 +        if !block.stmts.is_empty();
 +        then {
 +            let mut applicability = Applicability::MachineApplicable;
 +            let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
-                 format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str),
++            let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
 +            let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
 +            block_str.remove(0);
 +            block_str.pop();
 +            let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
 +
++            // Reference iterator from `&(mut) []` or `[].iter(_mut)()`.
++            if !prefix.is_empty() && (
++                // Precedence of internal expression is less than or equal to precedence of `&expr`.
++                arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
++            ) {
++                arg_snip = format!("({arg_snip})").into();
++            }
++
 +            span_lint_and_sugg(
 +                cx,
 +                SINGLE_ELEMENT_LOOP,
 +                expr.span,
 +                "for loop over a single element",
 +                "try",
++                format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"),
 +                applicability,
 +            )
 +        }
 +    }
 +}
index 0f6ac47843241d9cc3718d8548eea50ecb746b9b,0000000000000000000000000000000000000000..f552d5c1afab9268f4448af24acbd7e881cd2a84
mode 100644,000000..100644
--- /dev/null
@@@ -1,275 -1,0 +1,272 @@@
- use clippy_utils::source::snippet;
 +use clippy_utils::diagnostics::span_lint_and_then;
-             snippet(cx, var_arg.span, "_"),
-             snippet(cx, fn_arg.span, "_"),
++use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
 +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));
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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));
 +    /// };
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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 mut applicability = Applicability::MachineApplicable;
 +        let msg = suggestion_msg("function", map_type);
 +        let suggestion = format!(
 +            "if let {0}({binding}) = {1} {{ {2}({binding}) }}",
 +            variant,
-             diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::MachineApplicable);
++            snippet_with_applicability(cx, var_arg.span, "_", &mut applicability),
++            snippet_with_applicability(cx, fn_arg.span, "_", &mut applicability),
 +            binding = let_binding_name(cx, var_arg)
 +        );
 +
 +        span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
-                     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
++            diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
 +        });
 +    } 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 mut applicability = Applicability::MachineApplicable;
 +                let suggestion = format!(
 +                    "if let {0}({1}) = {2} {{ {3} }}",
 +                    variant,
++                    snippet_with_applicability(cx, binding.pat.span, "_", &mut applicability),
++                    snippet_with_applicability(cx, var_arg.span, "_", &mut applicability),
++                    snippet_with_context(cx, reduced_expr_span, var_arg.span.ctxt(), "_", &mut applicability).0,
 +                );
++                diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
 +            } 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 ff85623acf49b85eabdd4c4eb4e399e9537ceefa,0000000000000000000000000000000000000000..e93b494653fc05923feecace84790bb7606d6122
mode 100644,000000..100644
--- /dev/null
@@@ -1,793 -1,0 +1,793 @@@
-                     needless_match::check_match(cx, ex, arms);
 +use clippy_utils::source::{snippet_opt, walk_span_to_context};
 +use clippy_utils::{meets_msrv, msrvs};
 +use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 +use rustc_lexer::{tokenize, TokenKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{Span, SpanData, SyntaxContext};
 +
 +mod infalliable_detructuring_match;
 +mod match_as_ref;
 +mod match_bool;
 +mod match_like_matches;
 +mod match_ref_pats;
 +mod match_same_arms;
 +mod match_single_binding;
 +mod match_wild_enum;
 +mod match_wild_err_arm;
 +mod needless_match;
 +mod overlapping_arms;
 +mod redundant_pattern_match;
 +mod rest_pat_in_fully_bound_struct;
 +mod single_match;
 +mod wild_in_or_pats;
 +
 +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);
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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);
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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),
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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();
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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"),
 +    ///     _ => (),
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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"),
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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(_) => {},
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.34.0"]
 +    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 => {},
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    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" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    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;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    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);
 +    /// ```
 +    #[clippy::version = "1.43.0"]
 +    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 } => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.43.0"]
 +    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();
 +    /// ```
 +    #[clippy::version = "1.31.0"]
 +    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));
 +    /// ```
 +    #[clippy::version = "1.47.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(),
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MATCH_SAME_ARMS,
 +    pedantic,
 +    "`match` with identical arm bodies"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result`
 +    /// when function signatures are the same.
 +    ///
 +    /// ### Why is this bad?
 +    /// This `match` block does nothing and might not be what the coder intended.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// fn foo() -> Result<(), i32> {
 +    ///     match result {
 +    ///         Ok(val) => Ok(val),
 +    ///         Err(err) => Err(err),
 +    ///     }
 +    /// }
 +    ///
 +    /// fn bar() -> Option<i32> {
 +    ///     if let Some(val) = option {
 +    ///         Some(val)
 +    ///     } else {
 +    ///         None
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be replaced as
 +    ///
 +    /// ```rust,ignore
 +    /// fn foo() -> Result<(), i32> {
 +    ///     result
 +    /// }
 +    ///
 +    /// fn bar() -> Option<i32> {
 +    ///     option
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub NEEDLESS_MATCH,
 +    complexity,
 +    "`match` or match-like `if let` that are unnecessary"
 +}
 +
 +#[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,
 +    NEEDLESS_MATCH,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Matches {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Match(ex, arms, source) = expr.kind {
 +            if !contains_cfg_arm(cx, expr, ex, arms) {
 +                if source == MatchSource::Normal {
 +                    if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO)
 +                        && match_like_matches::check_match(cx, expr, ex, arms))
 +                    {
 +                        match_same_arms::check(cx, arms);
 +                    }
 +
 +                    redundant_pattern_match::check_match(cx, expr, ex, arms);
 +                    single_match::check(cx, ex, arms, expr);
 +                    match_bool::check(cx, ex, arms, expr);
 +                    overlapping_arms::check(cx, ex, arms);
 +                    match_wild_enum::check(cx, ex, arms);
 +                    match_as_ref::check(cx, ex, arms, expr);
++                    needless_match::check_match(cx, ex, arms, expr);
 +
 +                    if self.infallible_destructuring_match_linted {
 +                        self.infallible_destructuring_match_linted = false;
 +                    } else {
 +                        match_single_binding::check(cx, ex, arms, expr);
 +                    }
 +                }
 +                match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
 +            }
 +
 +            // These don't depend on a relationship between multiple arms
 +            match_wild_err_arm::check(cx, ex, arms);
 +            wild_in_or_pats::check(cx, arms);
 +        } else {
 +            if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
 +                match_like_matches::check(cx, expr);
 +            }
 +            redundant_pattern_match::check(cx, expr);
 +            needless_match::check(cx, expr);
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
 +        self.infallible_destructuring_match_linted |= infalliable_detructuring_match::check(cx, local);
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        rest_pat_in_fully_bound_struct::check(cx, pat);
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +/// Checks if there are any arms with a `#[cfg(..)]` attribute.
 +fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]) -> bool {
 +    let Some(scrutinee_span) = walk_span_to_context(scrutinee.span, SyntaxContext::root()) else {
 +        // Shouldn't happen, but treat this as though a `cfg` attribute were found
 +        return true;
 +    };
 +
 +    let start = scrutinee_span.hi();
 +    let mut arm_spans = arms.iter().map(|arm| {
 +        let data = arm.span.data();
 +        (data.ctxt == SyntaxContext::root()).then(|| (data.lo, data.hi))
 +    });
 +    let end = e.span.hi();
 +
 +    // Walk through all the non-code space before each match arm. The space trailing the final arm is
 +    // handled after the `try_fold` e.g.
 +    //
 +    // match foo {
 +    // _________^-                      everything between the scrutinee and arm1
 +    //|    arm1 => (),
 +    //|---^___________^                 everything before arm2
 +    //|    #[cfg(feature = "enabled")]
 +    //|    arm2 => some_code(),
 +    //|---^____________________^        everything before arm3
 +    //|    // some comment about arm3
 +    //|    arm3 => some_code(),
 +    //|---^____________________^        everything after arm3
 +    //|    #[cfg(feature = "disabled")]
 +    //|    arm4 = some_code(),
 +    //|};
 +    //|^
 +    let found = arm_spans.try_fold(start, |start, range| {
 +        let Some((end, next_start)) = range else {
 +            // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute were
 +            // found.
 +            return Err(());
 +        };
 +        let span = SpanData {
 +            lo: start,
 +            hi: end,
 +            ctxt: SyntaxContext::root(),
 +            parent: None,
 +        }
 +        .span();
 +        (!span_contains_cfg(cx, span)).then(|| next_start).ok_or(())
 +    });
 +    match found {
 +        Ok(start) => {
 +            let span = SpanData {
 +                lo: start,
 +                hi: end,
 +                ctxt: SyntaxContext::root(),
 +                parent: None,
 +            }
 +            .span();
 +            span_contains_cfg(cx, span)
 +        },
 +        Err(()) => true,
 +    }
 +}
 +
 +/// Checks if the given span contains a `#[cfg(..)]` attribute
 +fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
 +    let Some(snip) = snippet_opt(cx, s) else {
 +        // Assume true. This would require either an invalid span, or one which crosses file boundaries.
 +        return true;
 +    };
 +    let mut pos = 0usize;
 +    let mut iter = tokenize(&snip).map(|t| {
 +        let start = pos;
 +        pos += t.len;
 +        (t.kind, start..pos)
 +    });
 +
 +    // Search for the token sequence [`#`, `[`, `cfg`]
 +    while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
 +        let mut iter = iter.by_ref().skip_while(|(t, _)| {
 +            matches!(
 +                t,
 +                TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }
 +            )
 +        });
 +        if matches!(iter.next(), Some((TokenKind::OpenBracket, _)))
 +            && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg")
 +        {
 +            return true;
 +        }
 +    }
 +    false
 +}
index 76131d307d777e10e262cba3971b4b890a6c8c49,0000000000000000000000000000000000000000..2105a03e03a301cb8cca7aba53623766dd1fdc6e
mode 100644,000000..100644
--- /dev/null
@@@ -1,197 -1,0 +1,209 @@@
- use clippy_utils::ty::is_type_diagnostic_item;
- use clippy_utils::{eq_expr_value, get_parent_expr, higher, is_else_clause, is_lang_ctor, peel_blocks_with_stmt};
 +use super::NEEDLESS_MATCH;
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_applicability;
- use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, Pat, PatKind, Path, PathSegment, QPath, UnOp};
++use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
++use clippy_utils::{
++    eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_lang_ctor, over,
++    peel_blocks_with_stmt,
++};
 +use rustc_errors::Applicability;
 +use rustc_hir::LangItem::OptionNone;
- pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-     // This is for avoiding collision with `match_single_binding`.
-     if arms.len() < 2 {
-         return;
-     }
-     for arm in arms {
-         if let PatKind::Wild = arm.pat.kind {
-             let ret_expr = strip_return(arm.body);
-             if !eq_expr_value(cx, ex, ret_expr) {
-                 return;
-             }
-         } else if !pat_same_as_expr(arm.pat, arm.body) {
-             return;
-         }
-     }
-     if let Some(match_expr) = get_parent_expr(cx, ex) {
++use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath};
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
++use rustc_typeck::hir_ty_to_ty;
 +
-             match_expr.span,
++pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
++    if arms.len() > 1 && expr_ty_matches_p_ty(cx, ex, expr) && check_all_arms(cx, ex, arms) {
 +        let mut applicability = Applicability::MachineApplicable;
 +        span_lint_and_sugg(
 +            cx,
 +            NEEDLESS_MATCH,
-     if_chain! {
-         if let Some(ref if_let) = higher::IfLet::hir(cx, ex);
-         if !is_else_clause(cx.tcx, ex);
-         if check_if_let(cx, if_let);
-         then {
++            expr.span,
 +            "this match expression is unnecessary",
 +            "replace it with",
 +            snippet_with_applicability(cx, ex.span, "..", &mut applicability).to_string(),
 +            applicability,
 +        );
 +    }
 +}
 +
 +/// Check for nop `if let` expression that assembled as unnecessary match
 +///
 +/// ```rust,ignore
 +/// if let Some(a) = option {
 +///     Some(a)
 +/// } else {
 +///     None
 +/// }
 +/// ```
 +/// OR
 +/// ```rust,ignore
 +/// if let SomeEnum::A = some_enum {
 +///     SomeEnum::A
 +/// } else if let SomeEnum::B = some_enum {
 +///     SomeEnum::B
 +/// } else {
 +///     some_enum
 +/// }
 +/// ```
 +pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>) {
-             } else {
-                 return eq_expr_value(cx, if_let.let_expr, ret);
++    if let Some(ref if_let) = higher::IfLet::hir(cx, ex) {
++        if !is_else_clause(cx.tcx, ex) && expr_ty_matches_p_ty(cx, if_let.let_expr, ex) && check_if_let(cx, if_let) {
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                NEEDLESS_MATCH,
 +                ex.span,
 +                "this if-let expression is unnecessary",
 +                "replace it with",
 +                snippet_with_applicability(cx, if_let.let_expr.span, "..", &mut applicability).to_string(),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
++fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool {
++    for arm in arms {
++        let arm_expr = peel_blocks_with_stmt(arm.body);
++        if let PatKind::Wild = arm.pat.kind {
++            return eq_expr_value(cx, match_expr, strip_return(arm_expr));
++        } else if !pat_same_as_expr(arm.pat, arm_expr) {
++            return false;
++        }
++    }
++
++    true
++}
++
 +fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
 +    if let Some(if_else) = if_let.if_else {
 +        if !pat_same_as_expr(if_let.let_pat, peel_blocks_with_stmt(if_let.if_then)) {
 +            return false;
 +        }
 +
 +        // Recurrsively check for each `else if let` phrase,
 +        if let Some(ref nested_if_let) = higher::IfLet::hir(cx, if_else) {
 +            return check_if_let(cx, nested_if_let);
 +        }
 +
 +        if matches!(if_else.kind, ExprKind::Block(..)) {
 +            let else_expr = peel_blocks_with_stmt(if_else);
++            if matches!(else_expr.kind, ExprKind::Block(..)) {
++                return false;
++            }
 +            let ret = strip_return(else_expr);
 +            let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
 +            if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
 +                if let ExprKind::Path(ref qpath) = ret.kind {
 +                    return is_lang_ctor(cx, qpath, OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
 +                }
-             return true;
++                return true;
 +            }
-         (
-             PatKind::TupleStruct(QPath::Resolved(_, path), [first_pat, ..], _),
-             ExprKind::Call(call_expr, [first_param, ..]),
-         ) => {
++            return eq_expr_value(cx, if_let.let_expr, ret);
 +        }
 +    }
++
 +    false
 +}
 +
 +/// Strip `return` keyword if the expression type is `ExprKind::Ret`.
 +fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 +    if let ExprKind::Ret(Some(ret)) = expr.kind {
 +        ret
 +    } else {
 +        expr
 +    }
 +}
 +
++/// Manually check for coercion casting by checking if the type of the match operand or let expr
++/// differs with the assigned local variable or the funtion return type.
++fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
++    if let Some(p_node) = get_parent_node(cx.tcx, p_expr.hir_id) {
++        match p_node {
++            // Compare match_expr ty with local in `let local = match match_expr {..}`
++            Node::Local(local) => {
++                let results = cx.typeck_results();
++                return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr));
++            },
++            // compare match_expr ty with RetTy in `fn foo() -> RetTy`
++            Node::Item(..) => {
++                if let Some(fn_decl) = p_node.fn_decl() {
++                    if let FnRetTy::Return(ret_ty) = fn_decl.output {
++                        return same_type_and_consts(hir_ty_to_ty(cx.tcx, ret_ty), cx.typeck_results().expr_ty(expr));
++                    }
++                }
++            },
++            // check the parent expr for this whole block `{ match match_expr {..} }`
++            Node::Block(block) => {
++                if let Some(block_parent_expr) = get_parent_expr_for_hir(cx, block.hir_id) {
++                    return expr_ty_matches_p_ty(cx, expr, block_parent_expr);
++                }
++            },
++            // recursively call on `if xxx {..}` etc.
++            Node::Expr(p_expr) => {
++                return expr_ty_matches_p_ty(cx, expr, p_expr);
++            },
++            _ => {},
++        }
++    }
++    false
++}
++
 +fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
 +    let expr = strip_return(expr);
 +    match (&pat.kind, &expr.kind) {
 +        // Example: `Some(val) => Some(val)`
-                 if has_identical_segments(path.segments, call_path.segments)
-                     && has_same_non_ref_symbol(first_pat, first_param)
-                 {
-                     return true;
-                 }
++        (PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => {
 +            if let ExprKind::Path(QPath::Resolved(_, call_path)) = call_expr.kind {
-         // Example: `val => val`, or `ref val => *val`
-         (PatKind::Binding(annot, _, pat_ident, _), _) => {
-             let new_expr = if let (
-                 BindingAnnotation::Ref | BindingAnnotation::RefMut,
-                 ExprKind::Unary(UnOp::Deref, operand_expr),
-             ) = (annot, &expr.kind)
-             {
-                 operand_expr
-             } else {
-                 expr
-             };
-             if let ExprKind::Path(QPath::Resolved(
++                return over(path.segments, call_path.segments, |pat_seg, call_seg| {
++                    pat_seg.ident.name == call_seg.ident.name
++                }) && same_non_ref_symbols(tuple_params, call_params);
 +            }
 +        },
-             )) = new_expr.kind
-             {
-                 return pat_ident.name == first_seg.ident.name;
-             }
++        // Example: `val => val`
++        (
++            PatKind::Binding(annot, _, pat_ident, _),
++            ExprKind::Path(QPath::Resolved(
 +                _,
 +                Path {
 +                    segments: [first_seg, ..],
 +                    ..
 +                },
-             return has_identical_segments(p_path.segments, e_path.segments);
++            )),
++        ) => {
++            return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
++                && pat_ident.name == first_seg.ident.name;
 +        },
 +        // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
 +        (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
- fn has_identical_segments(left_segs: &[PathSegment<'_>], right_segs: &[PathSegment<'_>]) -> bool {
-     if left_segs.len() != right_segs.len() {
++            return over(p_path.segments, e_path.segments, |p_seg, e_seg| {
++                p_seg.ident.name == e_seg.ident.name
++            });
 +        },
 +        // Example: `5 => 5`
 +        (PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
 +            if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
 +                return pat_spanned.node == expr_spanned.node;
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    false
 +}
 +
-     for i in 0..left_segs.len() {
-         if left_segs[i].ident.name != right_segs[i].ident.name {
-             return false;
-         }
-     }
-     true
- }
++fn same_non_ref_symbols(pats: &[Pat<'_>], exprs: &[Expr<'_>]) -> bool {
++    if pats.len() != exprs.len() {
 +        return false;
 +    }
- fn has_same_non_ref_symbol(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
-     if_chain! {
-         if let PatKind::Binding(annot, _, pat_ident, _) = pat.kind;
-         if !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
-         if let ExprKind::Path(QPath::Resolved(_, Path {segments: [first_seg, ..], .. })) = expr.kind;
-         then {
-             return pat_ident.name == first_seg.ident.name;
 +
-     false
++    for i in 0..pats.len() {
++        if !pat_same_as_expr(&pats[i], &exprs[i]) {
++            return false;
 +        }
 +    }
 +
++    true
 +}
index 76eaedea8a0d229b1d5ff32282db7eb52ddfc1f0,0000000000000000000000000000000000000000..44857d61fef8f9461e03eca830e4adccf882ca88
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
-         &format!("called `.byte().nth()` on a `{}`", caller_type),
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use rustc_errors::Applicability;
 +use rustc_hir::Expr;
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +use super::BYTES_NTH;
 +
 +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
 +    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 +    let caller_type = if ty.is_str() {
 +        "str"
 +    } else if is_type_diagnostic_item(cx, ty, sym::String) {
 +        "String"
 +    } else {
 +        return;
 +    };
 +    let mut applicability = Applicability::MachineApplicable;
 +    span_lint_and_sugg(
 +        cx,
 +        BYTES_NTH,
 +        expr.span,
++        &format!("called `.bytes().nth()` on a `{}`", caller_type),
 +        "try",
 +        format!(
 +            "{}.as_bytes().get({})",
 +            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
 +            snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
 +        ),
 +        applicability,
 +    );
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..be9d4ad94fb8ef580e60fbd90f9454d2ed1a817b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++use super::ERR_EXPECT;
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::ty::implements_trait;
++use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item};
++use rustc_errors::Applicability;
++use rustc_lint::LateContext;
++use rustc_middle::ty;
++use rustc_middle::ty::Ty;
++use rustc_semver::RustcVersion;
++use rustc_span::{sym, Span};
++
++pub(super) fn check(
++    cx: &LateContext<'_>,
++    _expr: &rustc_hir::Expr<'_>,
++    recv: &rustc_hir::Expr<'_>,
++    msrv: Option<&RustcVersion>,
++    expect_span: Span,
++    err_span: Span,
++) {
++    if_chain! {
++        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
++        // Test the version to make sure the lint can be showed (expect_err has been
++        // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
++        if meets_msrv(msrv, &msrvs::EXPECT_ERR);
++
++        // Grabs the `Result<T, E>` type
++        let result_type = cx.typeck_results().expr_ty(recv);
++        // Tests if the T type in a `Result<T, E>` is not None
++        if let Some(data_type) = get_data_type(cx, result_type);
++        // Tests if the T type in a `Result<T, E>` implements debug
++        if has_debug_impl(data_type, cx);
++
++        then {
++            span_lint_and_sugg(
++                cx,
++                ERR_EXPECT,
++                err_span.to(expect_span),
++                "called `.err().expect()` on a `Result` value",
++                "try",
++                "expect_err".to_string(),
++                Applicability::MachineApplicable
++        );
++        }
++    };
++}
++
++/// Given a `Result<T, E>` type, return its data (`T`).
++fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
++    match ty.kind() {
++        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().next(),
++        _ => None,
++    }
++}
++
++/// Given a type, very if the Debug trait has been impl'd
++fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
++    cx.tcx
++        .get_diagnostic_item(sym::Debug)
++        .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
++}
index c98cdfbca434e9dd9bfbdcede516e322be519e97,0000000000000000000000000000000000000000..9651a52be4e7281a28a4891a942c5d415d3de761
mode 100644,000000..100644
--- /dev/null
@@@ -1,60 -1,0 +1,58 @@@
-         "to_vec" => {
-             cx.tcx.impl_of_method(method_def_id)
-                 .filter(|&impl_did| {
-                     cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
-                 })
-                 .is_some()
-         },
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_context;
 +use clippy_utils::ty::peel_mid_ty_refs;
 +use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_span::sym;
 +
 +use super::IMPLICIT_CLONE;
 +
 +pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
 +    if_chain! {
 +        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
 +        if is_clone_like(cx, method_name, method_def_id);
 +        let return_type = cx.typeck_results().expr_ty(expr);
 +        let input_type = cx.typeck_results().expr_ty(recv);
 +        let (input_type, ref_count) = peel_mid_ty_refs(input_type);
 +        if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
 +        if return_type == input_type;
 +        then {
 +            let mut app = Applicability::MachineApplicable;
 +            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
 +            span_lint_and_sugg(
 +                cx,
 +                IMPLICIT_CLONE,
 +                expr.span,
 +                &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name),
 +                "consider using",
 +                if ref_count > 1 {
 +                    format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip)
 +                } else {
 +                    format!("{}.clone()", recv_snip)
 +                },
 +                app,
 +            );
 +        }
 +    }
 +}
 +
 +/// Returns true if the named method can be used to clone the receiver.
 +/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
 +/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
 +/// `is_to_owned_like` in `unnecessary_to_owned.rs`.
 +pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
 +    match method_name {
 +        "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
 +        "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
 +        "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
++        "to_vec" => cx
++            .tcx
++            .impl_of_method(method_def_id)
++            .filter(|&impl_did| cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none())
++            .is_some(),
 +        _ => false,
 +    }
 +}
index b93f1399eaeed8e9c13692355049678cf450cb42,0000000000000000000000000000000000000000..54c9ca435a447d8e870403ecf78cc48a5ce7d09a
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,70 @@@
- use clippy_utils::ty::{get_iterator_item_ty, is_copy};
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet;
-     let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) {
-         Some(ty) => ty,
-         _ => return,
++use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy};
 +use itertools::Itertools;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_middle::ty;
++use rustc_span::sym;
 +use std::ops::Not;
 +
 +use super::ITER_OVEREAGER_CLONED;
 +use crate::redundant_clone::REDUNDANT_CLONE;
 +
 +/// lint overeager use of `cloned()` for `Iterator`s
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx hir::Expr<'_>,
 +    recv: &'tcx hir::Expr<'_>,
 +    name: &str,
 +    map_arg: &[hir::Expr<'_>],
 +) {
 +    // Check if it's iterator and get type associated with `Item`.
++    let inner_ty = if_chain! {
++        if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
++        let recv_ty = cx.typeck_results().expr_ty(recv);
++        if implements_trait(cx, recv_ty, iterator_trait_id, &[]);
++        if let Some(inner_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv));
++        then {
++            inner_ty
++        } else {
++            return;
++        }
 +    };
 +
 +    match inner_ty.kind() {
 +        ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {},
 +        _ => return,
 +    };
 +
 +    let (lint, preserve_cloned) = match name {
 +        "count" => (REDUNDANT_CLONE, false),
 +        _ => (ITER_OVEREAGER_CLONED, true),
 +    };
 +    let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
 +    let msg = format!(
 +        "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
 +        name,
 +        wildcard_params,
 +        name,
 +        wildcard_params,
 +        preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
 +    );
 +
 +    span_lint_and_sugg(
 +        cx,
 +        lint,
 +        expr.span,
 +        &msg,
 +        "try this",
 +        format!(
 +            "{}.{}({}){}",
 +            snippet(cx, recv.span, ".."),
 +            name,
 +            map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
 +            preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
index f112b500d3d296051a3c43033383e45bd92a1458,0000000000000000000000000000000000000000..862a9578e6ff26d76296e18ad7b78a9e53ec36d0
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,39 @@@
-                 "remove the call to `map`",
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{is_expr_identity_function, is_trait_method};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_lint::LateContext;
 +use rustc_span::{source_map::Span, sym};
 +
 +use super::MAP_IDENTITY;
 +
 +pub(super) fn check(
 +    cx: &LateContext<'_>,
 +    expr: &hir::Expr<'_>,
 +    caller: &hir::Expr<'_>,
 +    map_arg: &hir::Expr<'_>,
++    name: &str,
 +    _map_span: Span,
 +) {
 +    let caller_ty = cx.typeck_results().expr_ty(caller);
 +
 +    if_chain! {
 +        if is_trait_method(cx, expr, sym::Iterator)
 +            || is_type_diagnostic_item(cx, caller_ty, sym::Result)
 +            || is_type_diagnostic_item(cx, caller_ty, sym::Option);
 +        if is_expr_identity_function(cx, map_arg);
 +        if let Some(sugg_span) = expr.span.trim_start(caller.span);
 +        then {
 +            span_lint_and_sugg(
 +                cx,
 +                MAP_IDENTITY,
 +                sugg_span,
 +                "unnecessary map of the identity function",
++                &format!("remove the call to `{}`", name),
 +                String::new(),
 +                Applicability::MachineApplicable,
 +            )
 +        }
 +    }
 +}
index 9d4e1fa39940139b1c1248df21649db552b66cd7,0000000000000000000000000000000000000000..70d021a1668eb7ffb68b2cce0a79cc5c50d6195d
mode 100644,000000..100644
--- /dev/null
@@@ -1,2803 -1,0 +1,2861 @@@
-     /// `.collect::<String>()` is more concise and usually more performant
 +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 err_expect;
 +mod expect_fun_call;
 +mod expect_used;
 +mod extend_with_drain;
 +mod filetype_is_file;
 +mod filter_map;
 +mod filter_map_identity;
 +mod filter_map_next;
 +mod filter_next;
 +mod flat_map_identity;
 +mod flat_map_option;
 +mod from_iter_instead_of_collect;
 +mod get_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_overeager_cloned;
 +mod iter_skip_next;
 +mod iter_with_drain;
 +mod iterator_step_by_zero;
 +mod manual_saturating_arithmetic;
 +mod manual_str_repeat;
 +mod map_collect_result_unit;
 +mod map_flatten;
 +mod map_identity;
 +mod map_unwrap_or;
++mod needless_option_as_deref;
 +mod ok_expect;
 +mod option_as_ref_deref;
 +mod option_map_or_none;
 +mod option_map_unwrap_or;
 +mod or_fun_call;
 +mod or_then_unwrap;
 +mod search_is_some;
 +mod single_char_add_str;
 +mod single_char_insert_string;
 +mod single_char_pattern;
 +mod single_char_push_string;
 +mod skip_while_next;
 +mod str_splitn;
 +mod string_extend_chars;
 +mod suspicious_map;
 +mod suspicious_splitn;
 +mod uninit_assumed_init;
 +mod unnecessary_filter_map;
 +mod unnecessary_fold;
 +mod unnecessary_iter_cloned;
 +mod unnecessary_join;
 +mod unnecessary_lazy_eval;
 +mod unnecessary_to_owned;
 +mod unwrap_or_else_default;
 +mod unwrap_used;
 +mod useless_asref;
 +mod utils;
 +mod wrong_self_convention;
 +mod zst_offset;
 +
 +use bind_instead_of_map::BindInsteadOfMap;
 +use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
 +use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::def::Res;
 +use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, TraitRef, Ty};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{sym, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `cloned()` on an `Iterator` or `Option` where
 +    /// `copied()` could be used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `copied()` is better because it guarantees that the type being cloned
 +    /// implements `Copy`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1, 2, 3].iter().cloned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// [1, 2, 3].iter().copied();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub CLONED_INSTEAD_OF_COPIED,
 +    pedantic,
 +    "used `cloned` where `copied` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's often inefficient to clone all elements of an iterator, when eventually, only some
 +    /// of them will be consumed.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let vec = vec!["string".to_string()];
 +    ///
 +    /// // Bad
 +    /// vec.iter().cloned().take(10);
 +    ///
 +    /// // Good
 +    /// vec.iter().take(10).cloned();
 +    ///
 +    /// // Bad
 +    /// vec.iter().cloned().last();
 +    ///
 +    /// // Good
 +    /// vec.iter().last().cloned();
 +    ///
 +    /// ```
 +    /// ### Known Problems
 +    /// This `lint` removes the side of effect of cloning items in the iterator.
 +    /// A code that relies on that side-effect could fail.
 +    ///
 +    #[clippy::version = "1.59.0"]
 +    pub ITER_OVEREAGER_CLONED,
 +    perf,
 +    "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
 +    /// used instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// When applicable, `filter_map()` is more clear since it shows that
 +    /// `Option` is used to produce 0 or 1 items.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub FLAT_MAP_OPTION,
 +    pedantic,
 +    "used `flat_map` where `filter_map` could be used instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is better to handle the `None` or `Err` case,
 +    /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
 +    /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// `result.unwrap()` will let the thread panic on `Err` values.
 +    /// Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// Even if you want to panic on errors, not all `Error`s implement good
 +    /// messages on display. Therefore, it may be beneficial to look at the places
 +    /// where they may get displayed. Activate this lint to do just that.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.unwrap();
 +    ///
 +    /// // Good
 +    /// opt.expect("more helpful message");
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.unwrap();
 +    ///
 +    /// // Good
 +    /// res.expect("more helpful message");
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub UNWRAP_USED,
 +    restriction,
 +    "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.expect()` calls on `Option`s and `Result`s.
 +    ///
 +    /// ### Why is this bad?
 +    /// Usually it is better to handle the `None` or `Err` case.
 +    /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
 +    /// this lint is `Allow` by default.
 +    ///
 +    /// `result.expect()` will let the thread panic on `Err`
 +    /// values. Normally, you want to implement more sophisticated error handling,
 +    /// and propagate errors upwards with `?` operator.
 +    ///
 +    /// ### Examples
 +    /// ```rust,ignore
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.expect("one");
 +    ///
 +    /// // Good
 +    /// let opt = Some(1);
 +    /// opt?;
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let res: Result<usize, ()> = Ok(1);
 +    ///
 +    /// // Bad
 +    /// res.expect("one");
 +    ///
 +    /// // Good
 +    /// res?;
 +    /// # Ok::<(), ()>(())
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub EXPECT_USED,
 +    restriction,
 +    "using `.expect()` on `Result` or `Option`, which might be better handled"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods that should live in a trait
 +    /// implementation of a `std` trait (see [llogiq's blog
 +    /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
 +    /// information) instead of an inherent implementation.
 +    ///
 +    /// ### Why is this bad?
 +    /// Implementing the traits improve ergonomics for users of
 +    /// the code, often with very little cost. Also people seeing a `mul(...)`
 +    /// method
 +    /// may expect `*` to work equally, so you should have good reason to disappoint
 +    /// them.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct X;
 +    /// impl X {
 +    ///     fn add(&self, other: &X) -> X {
 +    ///         // ..
 +    /// # X
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SHOULD_IMPLEMENT_TRAIT,
 +    style,
 +    "defining a method that should be implementing a std trait"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for methods with certain name prefixes and which
 +    /// doesn't match how self is taken. The actual rules are:
 +    ///
 +    /// |Prefix |Postfix     |`self` taken           | `self` type  |
 +    /// |-------|------------|-----------------------|--------------|
 +    /// |`as_`  | none       |`&self` or `&mut self` | any          |
 +    /// |`from_`| none       | none                  | any          |
 +    /// |`into_`| none       |`self`                 | any          |
 +    /// |`is_`  | none       |`&self` or none        | any          |
 +    /// |`to_`  | `_mut`     |`&mut self`            | any          |
 +    /// |`to_`  | not `_mut` |`self`                 | `Copy`       |
 +    /// |`to_`  | not `_mut` |`&self`                | not `Copy`   |
 +    ///
 +    /// Note: Clippy doesn't trigger methods with `to_` prefix in:
 +    /// - Traits definition.
 +    /// Clippy can not tell if a type that implements a trait is `Copy` or not.
 +    /// - Traits implementation, when `&self` is taken.
 +    /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
 +    /// (see e.g. the `std::string::ToString` trait).
 +    ///
 +    /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
 +    ///
 +    /// Please find more info here:
 +    /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
 +    ///
 +    /// ### Why is this bad?
 +    /// Consistency breeds readability. If you follow the
 +    /// conventions, your users won't be surprised that they, e.g., need to supply a
 +    /// mutable reference to a `as_..` function.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct X;
 +    /// impl X {
 +    ///     fn as_str(self) -> &'static str {
 +    ///         // ..
 +    /// # ""
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub WRONG_SELF_CONVENTION,
 +    style,
 +    "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `ok().expect(..)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Because you usually call `expect()` on the `Result`
 +    /// directly to get a better error message.
 +    ///
 +    /// ### Known problems
 +    /// The error type needs to implement `Debug`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = Ok::<_, ()>(());
 +    ///
 +    /// // Bad
 +    /// x.ok().expect("why did I do this again?");
 +    ///
 +    /// // Good
 +    /// x.expect("why did I do this again?");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OK_EXPECT,
 +    style,
 +    "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
 +}
 +
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for `.err().expect()` calls on the `Result` type.
++    ///
++    /// ### Why is this bad?
++    /// `.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
++    ///
++    /// ### Example
++    /// ```should_panic
++    /// let x: Result<u32, &str> = Ok(10);
++    /// x.err().expect("Testing err().expect()");
++    /// ```
++    /// Use instead:
++    /// ```should_panic
++    /// let x: Result<u32, &str> = Ok(10);
++    /// x.expect_err("Testing expect_err");
++    /// ```
++    #[clippy::version = "1.61.0"]
++    pub ERR_EXPECT,
++    style,
++    r#"using `.err().expect("")` when `.expect_err("")` can be used"#
++}
++
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
 +    /// `Result` values.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written as `_.unwrap_or_default`, which is
 +    /// simpler and more concise.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let x = Some(1);
 +    ///
 +    /// // Bad
 +    /// x.unwrap_or_else(Default::default);
 +    /// x.unwrap_or_else(u32::default);
 +    ///
 +    /// // Good
 +    /// x.unwrap_or_default();
 +    /// ```
 +    #[clippy::version = "1.56.0"]
 +    pub UNWRAP_OR_ELSE_DEFAULT,
 +    style,
 +    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
 +    /// `result.map(_).unwrap_or_else(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, these can be written more concisely (resp.) as
 +    /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
 +    ///
 +    /// ### Known problems
 +    /// The order of the arguments is not in execution order
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// # let x = Some(1);
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or(0);
 +    ///
 +    /// // Good
 +    /// x.map_or(0, |a| a + 1);
 +    /// ```
 +    ///
 +    /// // or
 +    ///
 +    /// ```rust
 +    /// # let x: Result<usize, ()> = Ok(1);
 +    /// # fn some_function(foo: ()) -> usize { 1 }
 +    ///
 +    /// // Bad
 +    /// x.map(|a| a + 1).unwrap_or_else(some_function);
 +    ///
 +    /// // Good
 +    /// x.map_or_else(some_function, |a| a + 1);
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub MAP_UNWRAP_OR,
 +    pedantic,
 +    "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map_or(None, _)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.and_then(_)`.
 +    ///
 +    /// ### Known problems
 +    /// The order of the arguments is not in execution order.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let opt = Some(1);
 +    ///
 +    /// // Bad
 +    /// opt.map_or(None, |a| Some(a + 1));
 +    ///
 +    /// // Good
 +    /// opt.and_then(|a| Some(a + 1));
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OPTION_MAP_OR_NONE,
 +    style,
 +    "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map_or(None, Some)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.ok()`.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// # let r: Result<u32, &str> = Ok(1);
 +    /// assert_eq!(Some(1), r.map_or(None, Some));
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// # let r: Result<u32, &str> = Ok(1);
 +    /// assert_eq!(Some(1), r.ok());
 +    /// ```
 +    #[clippy::version = "1.44.0"]
 +    pub RESULT_MAP_OR_INTO_OPTION,
 +    style,
 +    "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
 +    /// `_.or_else(|x| Err(y))`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.map(|x| y)` or `_.map_err(|x| y)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn opt() -> Option<&'static str> { Some("42") }
 +    /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
 +    /// let _ = opt().and_then(|s| Some(s.len()));
 +    /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
 +    /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    ///
 +    /// ```rust
 +    /// # fn opt() -> Option<&'static str> { Some("42") }
 +    /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
 +    /// let _ = opt().map(|s| s.len());
 +    /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
 +    /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
 +    /// ```
 +    #[clippy::version = "1.45.0"]
 +    pub BIND_INSTEAD_OF_MAP,
 +    complexity,
 +    "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter(_).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().filter(|x| **x == 0).next();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub FILTER_NEXT,
 +    complexity,
 +    "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.skip_while(condition).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find(!condition)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().skip_while(|x| **x == 0).next();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// # let vec = vec![1];
 +    /// vec.iter().find(|x| **x != 0);
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub SKIP_WHILE_NEXT,
 +    complexity,
 +    "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![vec![1]];
 +    /// let opt = Some(5);
 +    ///
 +    /// // Bad
 +    /// vec.iter().map(|x| x.iter()).flatten();
 +    /// opt.map(|x| Some(x * 2)).flatten();
 +    ///
 +    /// // Good
 +    /// vec.iter().flat_map(|x| x.iter());
 +    /// opt.and_then(|x| Some(x * 2));
 +    /// ```
 +    #[clippy::version = "1.31.0"]
 +    pub MAP_FLATTEN,
 +    complexity,
 +    "using combinations of `flatten` and `map` which can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter(_).map(_)` that can be written more simply
 +    /// as `filter_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `filter` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .filter(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// (0_i32..10).filter_map(|n| n.checked_add(1));
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub MANUAL_FILTER_MAP,
 +    complexity,
 +    "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.find(_).map(_)` that can be written more simply
 +    /// as `find_map(_)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Redundant code in the `find` and `map` operations is poor style and
 +    /// less performant.
 +    ///
 +     /// ### Example
 +    /// Bad:
 +    /// ```rust
 +    /// (0_i32..10)
 +    ///     .find(|n| n.checked_add(1).is_some())
 +    ///     .map(|n| n.checked_add(1).unwrap());
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// (0_i32..10).find_map(|n| n.checked_add(1));
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub MANUAL_FIND_MAP,
 +    complexity,
 +    "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.filter_map(_).next()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.find_map(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
 +    /// ```
 +    /// Can be written as
 +    ///
 +    /// ```rust
 +    ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
 +    /// ```
 +    #[clippy::version = "1.36.0"]
 +    pub FILTER_MAP_NEXT,
 +    pedantic,
 +    "using combination of `filter_map` and `next` which can usually be written as a single method call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `flat_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flat_map(|x| x);
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let iter = vec![vec![0]].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub FLAT_MAP_IDENTITY,
 +    complexity,
 +    "call to `flat_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for an iterator or string search (such as `find()`,
 +    /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as:
 +    /// * `_.any(_)`, or `_.contains(_)` for `is_some()`,
 +    /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().find(|x| **x == 0).is_some();
 +    ///
 +    /// let _ = "hello world".find("world").is_none();
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let vec = vec![1];
 +    /// vec.iter().any(|x| *x == 0);
 +    ///
 +    /// let _ = !"hello world".contains("world");
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SEARCH_IS_SOME,
 +    complexity,
 +    "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.chars().next()` on a `str` to check
 +    /// if it starts with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.starts_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.chars().next() == Some('_') {};
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let name = "foo";
 +    /// if name.starts_with('_') {};
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHARS_NEXT_CMP,
 +    style,
 +    "using `.chars().next()` to check if a string starts with a char"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
 +    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
 +    /// `unwrap_or_default` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// The function will always be called and potentially
 +    /// allocate an object acting as the default.
 +    ///
 +    /// ### Known problems
 +    /// If the function has side-effects, not calling it will
 +    /// change the semantic of the program, but you shouldn't rely on that anyway.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or(String::new());
 +    /// ```
 +    /// this can instead be written:
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or_else(String::new);
 +    /// ```
 +    /// or
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// foo.unwrap_or_default();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub OR_FUN_CALL,
 +    perf,
 +    "using any `*or` method with a function call, which suggests `*or_else`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.or(…).unwrap()` calls to Options and Results.
 +    ///
 +    /// ### Why is this bad?
 +    /// You should use `.unwrap_or(…)` instead for clarity.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let fallback = "fallback";
 +    /// // Result
 +    /// # type Error = &'static str;
 +    /// # let result: Result<&str, Error> = Err("error");
 +    /// let value = result.or::<Error>(Ok(fallback)).unwrap();
 +    ///
 +    /// // Option
 +    /// # let option: Option<&str> = None;
 +    /// let value = option.or(Some(fallback)).unwrap();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let fallback = "fallback";
 +    /// // Result
 +    /// # let result: Result<&str, &str> = Err("error");
 +    /// let value = result.unwrap_or(fallback);
 +    ///
 +    /// // Option
 +    /// # let option: Option<&str> = None;
 +    /// let value = option.unwrap_or(fallback);
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub OR_THEN_UNWRAP,
 +    complexity,
 +    "checks for `.or(…).unwrap()` calls to Options and Results."
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
 +    /// etc., and suggests to use `unwrap_or_else` instead
 +    ///
 +    /// ### Why is this bad?
 +    /// The function will always be called.
 +    ///
 +    /// ### Known problems
 +    /// If the function has side-effects, not calling it will
 +    /// change the semantics of the program, but you shouldn't rely on that anyway.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// # let err_code = "418";
 +    /// # let err_msg = "I'm a teapot";
 +    /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
 +    /// ```
 +    /// or
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// # let err_code = "418";
 +    /// # let err_msg = "I'm a teapot";
 +    /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
 +    /// ```
 +    /// this can instead be written:
 +    /// ```rust
 +    /// # let foo = Some(String::new());
 +    /// # let err_code = "418";
 +    /// # let err_msg = "I'm a teapot";
 +    /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub EXPECT_FUN_CALL,
 +    perf,
 +    "using any `expect` method with a function call"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.clone()` on a `Copy` type.
 +    ///
 +    /// ### Why is this bad?
 +    /// The only reason `Copy` types implement `Clone` is for
 +    /// generics, not for using the `clone` method on a concrete type.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// 42u64.clone();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CLONE_ON_COPY,
 +    complexity,
 +    "using `clone` on a `Copy` type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.clone()` on a ref-counted pointer,
 +    /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
 +    /// function syntax instead (e.g., `Rc::clone(foo)`).
 +    ///
 +    /// ### Why is this bad?
 +    /// Calling '.clone()' on an Rc, Arc, or Weak
 +    /// can obscure the fact that only the pointer is being cloned, not the underlying
 +    /// data.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::rc::Rc;
 +    /// let x = Rc::new(1);
 +    ///
 +    /// // Bad
 +    /// x.clone();
 +    ///
 +    /// // Good
 +    /// Rc::clone(&x);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CLONE_ON_REF_PTR,
 +    restriction,
 +    "using 'clone' on a ref-counted pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.clone()` on an `&&T`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Cloning an `&&T` copies the inner `&T`, instead of
 +    /// cloning the underlying `T`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn main() {
 +    ///     let x = vec![1];
 +    ///     let y = &&x;
 +    ///     let z = y.clone();
 +    ///     println!("{:p} {:p}", *y, z); // prints out the same pointer
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CLONE_DOUBLE_REF,
 +    correctness,
 +    "using `clone` on `&&T`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.to_string()` on an `&&T` where
 +    /// `T` implements `ToString` directly (like `&&str` or `&&String`).
 +    ///
 +    /// ### Why is this bad?
 +    /// This bypasses the specialized implementation of
 +    /// `ToString` and instead goes through the more expensive string formatting
 +    /// facilities.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Generic implementation for `T: Display` is used (slow)
 +    /// ["foo", "bar"].iter().map(|s| s.to_string());
 +    ///
 +    /// // OK, the specialized impl is used
 +    /// ["foo", "bar"].iter().map(|&s| s.to_string());
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub INEFFICIENT_TO_STRING,
 +    pedantic,
 +    "using `to_string` on `&&T` where `T: ToString`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `new` not returning a type that contains `Self`.
 +    ///
 +    /// ### Why is this bad?
 +    /// As a convention, `new` methods are used to make a new
 +    /// instance of a type.
 +    ///
 +    /// ### Example
 +    /// In an impl block:
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct NotAFoo;
 +    /// impl Foo {
 +    ///     fn new() -> NotAFoo {
 +    /// # NotAFoo
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// struct Bar(Foo);
 +    /// impl Foo {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new() -> Bar {
 +    /// # Bar(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// # struct Foo;
 +    /// # struct FooError;
 +    /// impl Foo {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Result<Foo, FooError> {
 +    /// # Ok(Foo)
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Or in a trait definition:
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Bad. The type name must contain `Self`
 +    ///     fn new();
 +    /// }
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// pub trait Trait {
 +    ///     // Good. Return type contains `Self`
 +    ///     fn new() -> Self;
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub NEW_RET_NO_SELF,
 +    style,
 +    "not returning type containing `Self` in a `new` method"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for string methods that receive a single-character
 +    /// `str` as an argument, e.g., `_.split("x")`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Performing these methods using a `char` is faster than
 +    /// using a `str`.
 +    ///
 +    /// ### Known problems
 +    /// Does not catch multi-byte unicode characters.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// _.split("x");
 +    ///
 +    /// // Good
 +    /// _.split('x');
 +    #[clippy::version = "pre 1.29.0"]
 +    pub SINGLE_CHAR_PATTERN,
 +    perf,
 +    "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calling `.step_by(0)` on iterators which panics.
 +    ///
 +    /// ### Why is this bad?
 +    /// This very much looks like an oversight. Use `panic!()` instead if you
 +    /// actually intend to panic.
 +    ///
 +    /// ### Example
 +    /// ```rust,should_panic
 +    /// for x in (0..100).step_by(0) {
 +    ///     //..
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITERATOR_STEP_BY_ZERO,
 +    correctness,
 +    "using `Iterator::step_by(0)`, which will panic at runtime"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for indirect collection of populated `Option`
 +    ///
 +    /// ### Why is this bad?
 +    /// `Option` is like a collection of 0-1 things, so `flatten`
 +    /// automatically does this without suspicious-looking `unwrap` calls.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let _ = std::iter::empty::<Option<i32>>().flatten();
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub OPTION_FILTER_MAP,
 +    complexity,
 +    "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `iter.nth(0)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `iter.next()` is equivalent to
 +    /// `iter.nth(0)`, as they both consume the next element,
 +    ///  but is more readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// // Bad
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().nth(0);
 +    ///
 +    /// // Good
 +    /// # let mut s = HashSet::new();
 +    /// # s.insert(1);
 +    /// let x = s.iter().next();
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub ITER_NTH_ZERO,
 +    style,
 +    "replace `iter.nth(0)` with `iter.next()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.iter().nth()` (and the related
 +    /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.get()` and `.get_mut()` are more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.get(3);
 +    /// let bad_slice = &some_vec[..].get(3);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_NTH,
 +    perf,
 +    "using `.iter().nth()` on a standard library type with O(1) element access"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.skip(x).next()` on iterators.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.nth(x)` is cleaner
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().skip(3).next();
 +    /// let bad_slice = &some_vec[..].iter().skip(3).next();
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let bad_vec = some_vec.iter().nth(3);
 +    /// let bad_slice = &some_vec[..].iter().nth(3);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_SKIP_NEXT,
 +    style,
 +    "using `.skip(x).next()` on an iterator"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.into_iter()` is simpler with better performance.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// let mut foo = vec![0, 1, 2, 3];
 +    /// let bar: HashSet<usize> = foo.drain(..).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # use std::collections::HashSet;
 +    /// let foo = vec![0, 1, 2, 3];
 +    /// let bar: HashSet<usize> = foo.into_iter().collect();
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub ITER_WITH_DRAIN,
 +    nursery,
 +    "replace `.drain(..)` with `.into_iter()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.get().unwrap()` (or
 +    /// `.get_mut().unwrap`) on a standard library type which implements `Index`
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the Index trait (`[]`) is more clear and more
 +    /// concise.
 +    ///
 +    /// ### Known problems
 +    /// Not a replacement for error handling: Using either
 +    /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
 +    /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
 +    /// temporary placeholder for dealing with the `Option` type, then this does
 +    /// not mitigate the need for error handling. If there is a chance that `.get()`
 +    /// will be `None` in your program, then it is advisable that the `None` case
 +    /// is handled in a future refactor instead of using `.unwrap()` or the Index
 +    /// trait.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut some_vec = vec![0, 1, 2, 3];
 +    /// let last = some_vec.get(3).unwrap();
 +    /// *some_vec.get_mut(0).unwrap() = 1;
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let mut some_vec = vec![0, 1, 2, 3];
 +    /// let last = some_vec[3];
 +    /// some_vec[0] = 1;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub GET_UNWRAP,
 +    restriction,
 +    "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for occurrences where one vector gets extended instead of append
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `append` instead of `extend` is more concise and faster
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut a = vec![1, 2, 3];
 +    /// let mut b = vec![4, 5, 6];
 +    ///
 +    /// // Bad
 +    /// a.extend(b.drain(..));
 +    ///
 +    /// // Good
 +    /// a.append(&mut b);
 +    /// ```
 +    #[clippy::version = "1.55.0"]
 +    pub EXTEND_WITH_DRAIN,
 +    perf,
 +    "using vec.append(&mut vec) to move the full range of a vecor to another"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.extend(s.chars())` where s is a
 +    /// `&str` or `String`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.push_str(s)` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.extend(abc.chars());
 +    /// s.extend(def.chars());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let abc = "abc";
 +    /// let def = String::from("def");
 +    /// let mut s = String::new();
 +    /// s.push_str(abc);
 +    /// s.push_str(&def);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub STRING_EXTEND_CHARS,
 +    style,
 +    "using `x.extend(s.chars())` where s is a `&str` or `String`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.cloned().collect()` on slice to
 +    /// create a `Vec`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.to_vec()` is clearer
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s[..].iter().cloned().collect();
 +    /// ```
 +    /// The better use would be:
 +    /// ```rust
 +    /// let s = [1, 2, 3, 4, 5];
 +    /// let s2: Vec<isize> = s.to_vec();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub ITER_CLONED_COLLECT,
 +    style,
 +    "using `.cloned().collect()` on slice to create a `Vec`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.chars().last()` or
 +    /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.ends_with(_)`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let name = "_";
 +    ///
 +    /// // Bad
 +    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
 +    ///
 +    /// // Good
 +    /// name.ends_with('_') || name.ends_with('-');
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CHARS_LAST_CMP,
 +    style,
 +    "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `.as_ref()` or `.as_mut()` where the
 +    /// types before and after the call are the same.
 +    ///
 +    /// ### Why is this bad?
 +    /// The call is unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x.as_ref());
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// # fn do_stuff(x: &[i32]) {}
 +    /// let x: &[i32] = &[1, 2, 3, 4, 5];
 +    /// do_stuff(x);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USELESS_ASREF,
 +    complexity,
 +    "using `as_ref` where the types before and after the call are the same"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for using `fold` when a more succinct alternative exists.
 +    /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
 +    /// `sum` or `product`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
 +    /// ```
 +    /// This could be written as:
 +    /// ```rust
 +    /// let _ = (0..3).any(|x| x > 2);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNNECESSARY_FOLD,
 +    style,
 +    "using `fold` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `filter_map` calls that could be replaced by `filter` or `map`.
 +    /// More specifically it checks if the closure provided is only performing one of the
 +    /// filter or map operations and suggests the appropriate option.
 +    ///
 +    /// ### Why is this bad?
 +    /// Complexity. The intent is also clearer if only a single
 +    /// operation is being performed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
 +    ///
 +    /// // As there is no transformation of the argument this could be written as:
 +    /// let _ = (0..3).filter(|&x| x > 2);
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// let _ = (0..4).filter_map(|x| Some(x + 1));
 +    ///
 +    /// // As there is no conditional check on the argument this could be written as:
 +    /// let _ = (0..4).map(|x| x + 1);
 +    /// ```
 +    #[clippy::version = "1.31.0"]
 +    pub UNNECESSARY_FILTER_MAP,
 +    complexity,
 +    "using `filter_map` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `find_map` calls that could be replaced by `find` or `map`. More
 +    /// specifically it checks if the closure provided is only performing one of the
 +    /// find or map operations and suggests the appropriate option.
 +    ///
 +    /// ### Why is this bad?
 +    /// Complexity. The intent is also clearer if only a single
 +    /// operation is being performed.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
 +    ///
 +    /// // As there is no transformation of the argument this could be written as:
 +    /// let _ = (0..3).find(|&x| x > 2);
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// let _ = (0..4).find_map(|x| Some(x + 1));
 +    ///
 +    /// // As there is no conditional check on the argument this could be written as:
 +    /// let _ = (0..4).map(|x| x + 1).next();
 +    /// ```
 +    #[clippy::version = "1.61.0"]
 +    pub UNNECESSARY_FIND_MAP,
 +    complexity,
 +    "using `find_map` when a more succinct alternative exists"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `into_iter` calls on references which should be replaced by `iter`
 +    /// or `iter_mut`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability. Calling `into_iter` on a reference will not move out its
 +    /// content into the resulting iterator, which is confusing. It is better just call `iter` or
 +    /// `iter_mut` directly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let _ = (&vec![3, 4, 5]).into_iter();
 +    ///
 +    /// // Good
 +    /// let _ = (&vec![3, 4, 5]).iter();
 +    /// ```
 +    #[clippy::version = "1.32.0"]
 +    pub INTO_ITER_ON_REF,
 +    style,
 +    "using `.into_iter()` on a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `map` followed by a `count`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It looks suspicious. Maybe `map` was confused with `filter`.
 +    /// If the `map` call is intentional, this should be rewritten
 +    /// using `inspect`. Or, if you intend to drive the iterator to
 +    /// completion, you can just use `for_each` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (0..3).map(|x| x + 2).count();
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub SUSPICIOUS_MAP,
 +    suspicious,
 +    "suspicious usage of map"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `MaybeUninit::uninit().assume_init()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// For most types, this is undefined behavior.
 +    ///
 +    /// ### Known problems
 +    /// For now, we accept empty tuples and tuples / arrays
 +    /// of `MaybeUninit`. There may be other types that allow uninitialized
 +    /// data, but those are not yet rigorously defined.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Beware the UB
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
 +    /// ```
 +    ///
 +    /// Note that the following is OK:
 +    ///
 +    /// ```rust
 +    /// use std::mem::MaybeUninit;
 +    ///
 +    /// let _: [MaybeUninit<bool>; 5] = unsafe {
 +    ///     MaybeUninit::uninit().assume_init()
 +    /// };
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub UNINIT_ASSUMED_INIT,
 +    correctness,
 +    "`MaybeUninit::uninit().assume_init()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be written simply with `saturating_add/sub` methods.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let y: u32 = 0;
 +    /// # let x: u32 = 100;
 +    /// let add = x.checked_add(y).unwrap_or(u32::MAX);
 +    /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
 +    /// ```
 +    ///
 +    /// can be written using dedicated methods for saturating addition/subtraction as:
 +    ///
 +    /// ```rust
 +    /// # let y: u32 = 0;
 +    /// # let x: u32 = 100;
 +    /// let add = x.saturating_add(y);
 +    /// let sub = x.saturating_sub(y);
 +    /// ```
 +    #[clippy::version = "1.39.0"]
 +    pub MANUAL_SATURATING_ARITHMETIC,
 +    style,
 +    "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
 +    /// zero-sized types
 +    ///
 +    /// ### Why is this bad?
 +    /// This is a no-op, and likely unintended
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// unsafe { (&() as *const ()).offset(1) };
 +    /// ```
 +    #[clippy::version = "1.41.0"]
 +    pub ZST_OFFSET,
 +    correctness,
 +    "Check for offset calculations on raw pointers to zero-sized types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `FileType::is_file()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// When people testing a file type with `FileType::is_file`
 +    /// they are testing whether a path is something they can get bytes from. But
 +    /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
 +    /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # || {
 +    /// let metadata = std::fs::metadata("foo.txt")?;
 +    /// let filetype = metadata.file_type();
 +    ///
 +    /// if filetype.is_file() {
 +    ///     // read file
 +    /// }
 +    /// # Ok::<_, std::io::Error>(())
 +    /// # };
 +    /// ```
 +    ///
 +    /// should be written as:
 +    ///
 +    /// ```rust
 +    /// # || {
 +    /// let metadata = std::fs::metadata("foo.txt")?;
 +    /// let filetype = metadata.file_type();
 +    ///
 +    /// if !filetype.is_dir() {
 +    ///     // read file
 +    /// }
 +    /// # Ok::<_, std::io::Error>(())
 +    /// # };
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub FILETYPE_IS_FILE,
 +    restriction,
 +    "`FileType::is_file` is not recommended to test for readable file type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely as
 +    /// `_.as_deref()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_ref().map(String::as_str)
 +    /// # ;
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// # let opt = Some("".to_string());
 +    /// opt.as_deref()
 +    /// # ;
 +    /// ```
 +    #[clippy::version = "1.42.0"]
 +    pub OPTION_AS_REF_DEREF,
 +    complexity,
 +    "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `iter().next()` on a Slice or an Array
 +    ///
 +    /// ### Why is this bad?
 +    /// These can be shortened into `.get()`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a[2..].iter().next();
 +    /// b.iter().next();
 +    /// ```
 +    /// should be written as:
 +    /// ```rust
 +    /// # let a = [1, 2, 3];
 +    /// # let b = vec![1, 2, 3];
 +    /// a.get(2);
 +    /// b.get(0);
 +    /// ```
 +    #[clippy::version = "1.46.0"]
 +    pub ITER_NEXT_SLICE,
 +    style,
 +    "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns when using `push_str`/`insert_str` with a single-character string literal
 +    /// where `push`/`insert` with a `char` would work fine.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's less clear that we are pushing a single character.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut string = String::new();
 +    /// string.insert_str(0, "R");
 +    /// string.push_str("R");
 +    /// ```
 +    /// Could be written as
 +    /// ```rust
 +    /// let mut string = String::new();
 +    /// string.insert(0, 'R');
 +    /// string.push('R');
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub SINGLE_CHAR_ADD_STR,
 +    style,
 +    "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// As the counterpart to `or_fun_call`, this lint looks for unnecessary
 +    /// lazily evaluated closures on `Option` and `Result`.
 +    ///
 +    /// This lint suggests changing the following functions, when eager evaluation results in
 +    /// simpler code:
 +    ///  - `unwrap_or_else` to `unwrap_or`
 +    ///  - `and_then` to `and`
 +    ///  - `or_else` to `or`
 +    ///  - `get_or_insert_with` to `get_or_insert`
 +    ///  - `ok_or_else` to `ok_or`
 +    ///
 +    /// ### Why is this bad?
 +    /// Using eager evaluation is shorter and simpler in some cases.
 +    ///
 +    /// ### Known problems
 +    /// It is possible, but not recommended for `Deref` and `Index` to have
 +    /// side effects. Eagerly evaluating them can change the semantics of the program.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or_else(|| 42);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let opt: Option<u32> = None;
 +    ///
 +    /// opt.unwrap_or(42);
 +    /// ```
 +    #[clippy::version = "1.48.0"]
 +    pub UNNECESSARY_LAZY_EVALUATIONS,
 +    style,
 +    "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `_.map(_).collect::<Result<(), _>()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `try_for_each` instead is more readable and idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// (0..3).try_for_each(|t| Err(t));
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub MAP_COLLECT_RESULT_UNIT,
 +    style,
 +    "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `from_iter()` function calls on types that implement the `FromIterator`
 +    /// trait.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is recommended style to use collect. See
 +    /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::iter::FromIterator;
 +    ///
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v = Vec::from_iter(five_fives);
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let five_fives = std::iter::repeat(5).take(5);
 +    ///
 +    /// let v: Vec<i32> = five_fives.collect();
 +    ///
 +    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 +    /// ```
 +    #[clippy::version = "1.49.0"]
 +    pub FROM_ITER_INSTEAD_OF_COLLECT,
 +    pedantic,
 +    "use `.collect()` instead of `::from_iter()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `inspect().for_each()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is the same as performing the computation
 +    /// inside `inspect` at the beginning of the closure in `for_each`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .inspect(|&x| println!("inspect the number: {}", x))
 +    /// .for_each(|&x| {
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    /// Can be written as
 +    /// ```rust
 +    /// [1,2,3,4,5].iter()
 +    /// .for_each(|&x| {
 +    ///     println!("inspect the number: {}", x);
 +    ///     assert!(x >= 0);
 +    /// });
 +    /// ```
 +    #[clippy::version = "1.51.0"]
 +    pub INSPECT_FOR_EACH,
 +    complexity,
 +    "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `filter_map(|x| x)`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability, this can be written more concisely by using `flatten`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.filter_map(|x| x);
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let iter = vec![Some(1)].into_iter();
 +    /// iter.flatten();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub FILTER_MAP_IDENTITY,
 +    complexity,
 +    "call to `filter_map` where `flatten` is sufficient"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for instances of `map(f)` where `f` is the identity function.
 +    ///
 +    /// ### Why is this bad?
 +    /// It can be written more concisely without the call to `map`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let x = [1, 2, 3];
 +    /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub MAP_IDENTITY,
 +    complexity,
 +    "using iterator.map(|x| x)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.bytes().nth()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.as_bytes().get()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let _ = "Hello".bytes().nth(3);
 +    ///
 +    /// // Good
 +    /// let _ = "Hello".as_bytes().get(3);
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub BYTES_NTH,
 +    style,
 +    "replace `.bytes().nth()` with `.as_bytes().get()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
 +    ///
 +    /// ### Why is this bad?
 +    /// These methods do the same thing as `_.clone()` but may be confusing as
 +    /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.to_vec();
 +    /// let c = a.to_owned();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let a = vec![1, 2, 3];
 +    /// let b = a.clone();
 +    /// let c = a.clone();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub IMPLICIT_CLONE,
 +    pedantic,
 +    "implicitly cloning a value by invoking a function on its dereferenced type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `.iter().count()`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `.len()` is more efficient and more
 +    /// readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.iter().count();
 +    /// let _ = &some_vec[..].iter().count();
 +    ///
 +    /// // Good
 +    /// let some_vec = vec![0, 1, 2, 3];
 +    /// let _ = some_vec.len();
 +    /// let _ = &some_vec[..].len();
 +    /// ```
 +    #[clippy::version = "1.52.0"]
 +    pub ITER_COUNT,
 +    complexity,
 +    "replace `.iter().count()` with `.len()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to [`splitn`]
 +    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
 +    /// related functions with either zero or one splits.
 +    ///
 +    /// ### Why is this bad?
 +    /// These calls don't actually split the value and are
 +    /// likely to be intended as a different number.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let s = "";
 +    /// for x in s.splitn(1, ":") {
 +    ///     // use x
 +    /// }
 +    ///
 +    /// // Good
 +    /// let s = "";
 +    /// for x in s.splitn(2, ":") {
 +    ///     // use x
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub SUSPICIOUS_SPLITN,
 +    correctness,
 +    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for manual implementations of `str::repeat`
 +    ///
 +    /// ### Why is this bad?
 +    /// These are both harder to read, as well as less performant.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let x: String = std::iter::repeat('x').take(10).collect();
 +    ///
 +    /// // Good
 +    /// let x: String = "x".repeat(10);
 +    /// ```
 +    #[clippy::version = "1.54.0"]
 +    pub MANUAL_STR_REPEAT,
 +    perf,
 +    "manual implementation of `str::repeat`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `str::splitn(2, _)`
 +    ///
 +    /// ### Why is this bad?
 +    /// `split_once` is both clearer in intent and slightly more efficient.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    ///  let (key, value) = _.splitn(2, '=').next_tuple()?;
 +    ///  let value = _.splitn(2, '=').nth(1)?;
 +    ///
 +    /// // Good
 +    /// let (key, value) = _.split_once('=')?;
 +    /// let value = _.split_once('=')?.1;
 +    /// ```
 +    #[clippy::version = "1.57.0"]
 +    pub MANUAL_SPLIT_ONCE,
 +    complexity,
 +    "replace `.splitn(2, pat)` with `.split_once(pat)`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
 +    /// ### Why is this bad?
 +    /// The function `split` is simpler and there is no performance difference in these cases, considering
 +    /// that both functions return a lazy iterator.
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let str = "key=value=add";
 +    /// let _ = str.splitn(3, '=').next().unwrap();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // Good
 +    /// let str = "key=value=add";
 +    /// let _ = str.split('=').next().unwrap();
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub NEEDLESS_SPLITN,
 +    complexity,
 +    "usages of `str::splitn` that can be replaced with `str::split`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
 +    /// and other `to_owned`-like functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// The unnecessary calls result in useless allocations.
 +    ///
 +    /// ### Known problems
 +    /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
 +    /// owned copy of a resource and the resource is later used mutably. See
 +    /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let path = std::path::Path::new("x");
 +    /// foo(&path.to_string_lossy().to_string());
 +    /// fn foo(s: &str) {}
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let path = std::path::Path::new("x");
 +    /// foo(&path.to_string_lossy());
 +    /// fn foo(s: &str) {}
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub UNNECESSARY_TO_OWNED,
 +    perf,
 +    "unnecessary calls to `to_owned`-like functions"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for use of `.collect::<Vec<String>>().join("")` on iterators.
 +    ///
 +    /// ### Why is this bad?
-     /// While `.collect::<String>()` is more performant in most cases, there are cases where
++    /// `.collect::<String>()` is more concise and might be more performant
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let vector = vec!["hello",  "world"];
 +    /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
 +    /// println!("{}", output);
 +    /// ```
 +    /// The correct use would be:
 +    /// ```rust
 +    /// let vector = vec!["hello",  "world"];
 +    /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
 +    /// println!("{}", output);
 +    /// ```
 +    /// ### Known problems
-             ("map", [m_arg]) => {
++    /// While `.collect::<String>()` is sometimes more performant, there are cases where
 +    /// using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
 +    /// will prevent loop unrolling and will result in a negative performance impact.
++    ///
++    /// Additionlly, differences have been observed between aarch64 and x86_64 assembly output,
++    /// with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
 +    #[clippy::version = "1.61.0"]
 +    pub UNNECESSARY_JOIN,
 +    pedantic,
 +    "using `.collect::<Vec<String>>().join(\"\")` on an iterator"
 +}
 +
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
++    /// for example, `Option<&T>::as_deref()` returns the same type.
++    ///
++    /// ### Why is this bad?
++    /// Redundant code and improving readability.
++    ///
++    /// ### Example
++    /// ```rust
++    /// let a = Some(&1);
++    /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
++    /// ```
++    /// Could be written as:
++    /// ```rust
++    /// let a = Some(&1);
++    /// let b = a;
++    /// ```
++    #[clippy::version = "1.57.0"]
++    pub NEEDLESS_OPTION_AS_DEREF,
++    complexity,
++    "no-op use of `deref` or `deref_mut` method to `Option`."
++}
++
 +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,
 +    OR_THEN_UNWRAP,
 +    EXPECT_FUN_CALL,
 +    CHARS_NEXT_CMP,
 +    CHARS_LAST_CMP,
 +    CLONE_ON_COPY,
 +    CLONE_ON_REF_PTR,
 +    CLONE_DOUBLE_REF,
 +    ITER_OVEREAGER_CLONED,
 +    CLONED_INSTEAD_OF_COPIED,
 +    FLAT_MAP_OPTION,
 +    INEFFICIENT_TO_STRING,
 +    NEW_RET_NO_SELF,
 +    SINGLE_CHAR_PATTERN,
 +    SINGLE_CHAR_ADD_STR,
 +    SEARCH_IS_SOME,
 +    FILTER_NEXT,
 +    SKIP_WHILE_NEXT,
 +    FILTER_MAP_IDENTITY,
 +    MAP_IDENTITY,
 +    MANUAL_FILTER_MAP,
 +    MANUAL_FIND_MAP,
 +    OPTION_FILTER_MAP,
 +    FILTER_MAP_NEXT,
 +    FLAT_MAP_IDENTITY,
 +    MAP_FLATTEN,
 +    ITERATOR_STEP_BY_ZERO,
 +    ITER_NEXT_SLICE,
 +    ITER_COUNT,
 +    ITER_NTH,
 +    ITER_NTH_ZERO,
 +    BYTES_NTH,
 +    ITER_SKIP_NEXT,
 +    GET_UNWRAP,
 +    STRING_EXTEND_CHARS,
 +    ITER_CLONED_COLLECT,
 +    ITER_WITH_DRAIN,
 +    USELESS_ASREF,
 +    UNNECESSARY_FOLD,
 +    UNNECESSARY_FILTER_MAP,
 +    UNNECESSARY_FIND_MAP,
 +    INTO_ITER_ON_REF,
 +    SUSPICIOUS_MAP,
 +    UNINIT_ASSUMED_INIT,
 +    MANUAL_SATURATING_ARITHMETIC,
 +    ZST_OFFSET,
 +    FILETYPE_IS_FILE,
 +    OPTION_AS_REF_DEREF,
 +    UNNECESSARY_LAZY_EVALUATIONS,
 +    MAP_COLLECT_RESULT_UNIT,
 +    FROM_ITER_INSTEAD_OF_COLLECT,
 +    INSPECT_FOR_EACH,
 +    IMPLICIT_CLONE,
 +    SUSPICIOUS_SPLITN,
 +    MANUAL_STR_REPEAT,
 +    EXTEND_WITH_DRAIN,
 +    MANUAL_SPLIT_ONCE,
 +    NEEDLESS_SPLITN,
 +    UNNECESSARY_TO_OWNED,
 +    UNNECESSARY_JOIN,
++    ERR_EXPECT,
++    NEEDLESS_OPTION_AS_DEREF,
 +]);
 +
 +/// Extracts a method call name, args, and `Span` of the method name.
 +fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
 +    if let ExprKind::MethodCall(path, args, _) = recv.kind {
 +        if !args.iter().any(|e| e.span.from_expansion()) {
 +            let name = path.ident.name.as_str();
 +            return Some((name, args, path.ident.span));
 +        }
 +    }
 +    None
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Methods {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        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, args, _) => {
 +                let method_span = method_call.ident.span;
 +                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
 +                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
 +                clone_on_copy::check(cx, expr, method_call.ident.name, args);
 +                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
 +                inefficient_to_string::check(cx, expr, method_call.ident.name, args);
 +                single_char_add_str::check(cx, expr, args);
 +                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
 +                single_char_pattern::check(cx, expr, method_call.ident.name, args);
 +                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
 +            },
 +            hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
 +                let mut info = BinaryExprInfo {
 +                    expr,
 +                    chain: lhs,
 +                    other: rhs,
 +                    eq: op.node == hir::BinOpKind::Eq,
 +                };
 +                lint_binary_expr_with_method_call(cx, &mut info);
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_lines)]
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
 +        if in_external_macro(cx.sess(), impl_item.span) {
 +            return;
 +        }
 +        let name = impl_item.ident.name.as_str();
 +        let parent = cx.tcx.hir().get_parent_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(ret_ty, self_adt) {
 +                    return;
 +                }
 +            } else if contains_ty(ret_ty, self_ty) {
 +                return;
 +            }
 +
 +            // if return type is impl trait, check the associated types
 +            if let ty::Opaque(def_id, _) = *ret_ty.kind() {
 +                // one of the associated types must be Self
 +                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
 +                    if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
 +                        let assoc_ty = match projection_predicate.term {
 +                            ty::Term::Ty(ty) => ty,
 +                            ty::Term::Const(_c) => continue,
 +                        };
 +                        // walk the associated type and check for Self
 +                        if let Some(self_adt) = self_ty.ty_adt_def() {
 +                            if contains_adt_constructor(assoc_ty, self_adt) {
 +                                return;
 +                            }
 +                        } else if contains_ty(assoc_ty, self_ty) {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +
 +            if name == "new" && ret_ty != self_ty {
 +                span_lint(
 +                    cx,
 +                    NEW_RET_NO_SELF,
 +                    impl_item.span,
 +                    "methods called `new` usually return `Self`",
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let TraitItemKind::Fn(ref sig, _) = item.kind;
 +            if sig.decl.implicit_self.has_implicit_self();
 +            if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
 +
 +            then {
 +                let first_arg_span = first_arg_ty.span;
 +                let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
 +                let self_ty = TraitRef::identity(cx.tcx, item.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(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_deref" | "as_deref_mut", []) => {
++                needless_option_as_deref::check(cx, expr, recv, name);
++            },
 +            ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
 +            ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
 +            ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
 +            ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
 +            ("collect", []) => match method_call(recv) {
 +                Some((name @ ("cloned" | "copied"), [recv2], _)) => {
 +                    iter_cloned_collect::check(cx, name, expr, recv2);
 +                },
 +                Some(("map", [m_recv, m_arg], _)) => {
 +                    map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
 +                },
 +                Some(("take", [take_self_arg, take_arg], _)) => {
 +                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
 +                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
 +                    }
 +                },
 +                _ => {},
 +            },
 +            (name @ "count", args @ []) => match method_call(recv) {
 +                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
 +                Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
 +                    iter_count::check(cx, expr, recv2, name2);
 +                },
 +                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
 +                _ => {},
 +            },
 +            ("drain", [arg]) => {
 +                iter_with_drain::check(cx, expr, recv, span, arg);
 +            },
 +            ("expect", [_]) => match method_call(recv) {
 +                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
++                Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
 +                _ => 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, name);
 +                filter_map_identity::check(cx, expr, arg, span);
 +            },
 +            ("find_map", [arg]) => {
 +                unnecessary_filter_map::check(cx, expr, arg, name);
 +            },
 +            ("flat_map", [arg]) => {
 +                flat_map_identity::check(cx, expr, arg, span);
 +                flat_map_option::check(cx, expr, arg, span);
 +            },
 +            (name @ "flatten", args @ []) => match method_call(recv) {
 +                Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
 +                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
 +                _ => {},
 +            },
 +            ("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),
 +            ("join", [join_arg]) => {
 +                if let Some(("collect", _, span)) = method_call(recv) {
 +                    unnecessary_join::check(cx, expr, recv, join_arg, span);
 +                }
 +            },
 +            ("last", args @ []) | ("skip", args @ [_]) => {
 +                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
 +                    if let ("cloned", []) = (name2, args2) {
 +                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
 +                    }
 +                }
 +            },
-                 map_identity::check(cx, expr, recv, m_arg, span);
++            (name @ ("map" | "map_err"), [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, name, span);
 +            },
 +            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
 +            (name @ "next", args @ []) => {
 +                if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
 +                    match (name2, args2) {
 +                        ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
 +                        ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
 +                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
 +                        ("iter", []) => iter_next_slice::check(cx, expr, recv2),
 +                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
 +                        ("skip_while", [_]) => skip_while_next::check(cx, expr),
 +                        _ => {},
 +                    }
 +                }
 +            },
 +            ("nth", args @ [n_arg]) => match method_call(recv) {
 +                Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
 +                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
 +                Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
 +                Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
 +                _ => iter_nth_zero::check(cx, expr, recv, n_arg),
 +            },
 +            ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
 +            ("or_else", [arg]) => {
 +                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
 +                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
 +                }
 +            },
 +            ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
 +                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
 +                    suspicious_splitn::check(cx, name, expr, recv, count);
 +                    if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
 +                        str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg);
 +                    }
 +                    if count >= 2 {
 +                        str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count);
 +                    }
 +                }
 +            },
 +            ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
 +                if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
 +                    suspicious_splitn::check(cx, name, expr, recv, count);
 +                }
 +            },
 +            ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
 +            ("take", args @ [_arg]) => {
 +                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
 +                    if let ("cloned", []) = (name2, args2) {
 +                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
 +                    }
 +                }
 +            },
 +            ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
 +                implicit_clone::check(cx, name, expr, recv);
 +            },
 +            ("unwrap", []) => {
 +                match method_call(recv) {
 +                    Some(("get", [recv, get_arg], _)) => {
 +                        get_unwrap::check(cx, expr, recv, get_arg, false);
 +                    },
 +                    Some(("get_mut", [recv, get_arg], _)) => {
 +                        get_unwrap::check(cx, expr, recv, get_arg, true);
 +                    },
 +                    Some(("or", [recv, or_arg], or_span)) => {
 +                        or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
 +                    },
 +                    _ => {},
 +                }
 +                unwrap_used::check(cx, expr, recv);
 +            },
 +            ("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()])
 +        }
 +
 +        fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
 +            !matches_value(cx, parent_ty, ty)
 +                && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty)
 +                && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty)
 +        }
 +
 +        match self {
 +            Self::Value => matches_value(cx, parent_ty, ty),
 +            Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
 +            Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
 +            Self::No => matches_none(cx, parent_ty, ty),
 +        }
 +    }
 +
 +    #[must_use]
 +    fn description(self) -> &'static str {
 +        match self {
 +            Self::Value => "`self` by value",
 +            Self::Ref => "`self` by reference",
 +            Self::RefMut => "`self` by mutable reference",
 +            Self::No => "no `self`",
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum OutType {
 +    Unit,
 +    Bool,
 +    Any,
 +    Ref,
 +}
 +
 +impl OutType {
 +    fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
 +        let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
 +        match (self, ty) {
 +            (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
 +            (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
 +            (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
 +            (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
 +            (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn 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 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7030baf19ff5cf9bd9fd714a8ac9e319e957a54d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,37 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::path_res;
++use clippy_utils::source::snippet_opt;
++use clippy_utils::ty::is_type_diagnostic_item;
++use clippy_utils::usage::local_used_after_expr;
++use rustc_errors::Applicability;
++use rustc_hir::def::Res;
++use rustc_hir::Expr;
++use rustc_lint::LateContext;
++use rustc_span::sym;
++
++use super::NEEDLESS_OPTION_AS_DEREF;
++
++pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) {
++    let typeck = cx.typeck_results();
++    let outer_ty = typeck.expr_ty(expr);
++
++    if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
++        if name == "as_deref_mut" && recv.is_syntactic_place_expr() {
++            let Res::Local(binding_id) = path_res(cx, recv) else { return };
++
++            if local_used_after_expr(cx, binding_id, recv) {
++                return;
++            }
++        }
++
++        span_lint_and_sugg(
++            cx,
++            NEEDLESS_OPTION_AS_DEREF,
++            expr.span,
++            "derefed type is same as origin",
++            "try this",
++            snippet_opt(cx, recv.span).unwrap(),
++            Applicability::MachineApplicable,
++        );
++    }
++}
index b8dfe996880661e118ec06aa357a4606a4d1815b,0000000000000000000000000000000000000000..0a393657267b07833371498eb52b5015faf8c874
mode 100644,000000..100644
--- /dev/null
@@@ -1,180 -1,0 +1,166 @@@
- use std::{
-     ffi::OsString,
-     path::{Component, Path},
- };
 +use rustc_ast::ast;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext};
++use std::ffi::OsStr;
++use std::path::{Component, Path};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
-     /// Checks that module layout uses only self named module files, bans mod.rs files.
++    /// Checks that module layout uses only self named module files, bans `mod.rs` files.
 +    ///
 +    /// ### Why is this bad?
 +    /// Having multiple module layout styles in a project can be confusing.
 +    ///
 +    /// ### Example
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///     mod.rs
 +    ///   lib.rs
 +    /// ```
 +    /// Use instead:
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///   stuff.rs
 +    ///   lib.rs
 +    /// ```
 +    #[clippy::version = "1.57.0"]
 +    pub MOD_MODULE_FILES,
 +    restriction,
 +    "checks that module layout is consistent"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
-     /// Checks that module layout uses only mod.rs files.
++    /// Checks that module layout uses only `mod.rs` files.
 +    ///
 +    /// ### Why is this bad?
 +    /// Having multiple module layout styles in a project can be confusing.
 +    ///
 +    /// ### Example
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///   stuff.rs
 +    ///   lib.rs
 +    /// ```
 +    /// Use instead:
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///     mod.rs
 +    ///   lib.rs
 +    /// ```
 +
 +    #[clippy::version = "1.57.0"]
 +    pub SELF_NAMED_MODULE_FILES,
 +    restriction,
 +    "checks that module layout is consistent"
 +}
 +
 +pub struct ModStyle;
 +
 +impl_lint_pass!(ModStyle => [MOD_MODULE_FILES, SELF_NAMED_MODULE_FILES]);
 +
 +impl EarlyLintPass for ModStyle {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
 +        if cx.builder.lint_level(MOD_MODULE_FILES).0 == Level::Allow
 +            && cx.builder.lint_level(SELF_NAMED_MODULE_FILES).0 == Level::Allow
 +        {
 +            return;
 +        }
 +
 +        let files = cx.sess().source_map().files();
 +
-         let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess().opts.working_dir {
-             p.to_string_lossy()
-         } else {
-             return;
-         };
++        let RealFileName::LocalPath(trim_to_src) = &cx.sess().opts.working_dir else { return };
 +
 +        // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
 +        // `[path, to]` but not foo
 +        let mut folder_segments = FxHashSet::default();
 +        // `mod_folders` is all the unique folder names that contain a mod.rs file
 +        let mut mod_folders = FxHashSet::default();
 +        // `file_map` maps file names to the full path including the file name
 +        // `{ foo => path/to/foo.rs, .. }
 +        let mut file_map = FxHashMap::default();
 +        for file in files.iter() {
-             match &file.name {
-                 FileName::Real(RealFileName::LocalPath(lp))
-                     if lp.to_string_lossy().starts_with(trim_to_src.as_ref()) =>
-                 {
-                     let p = lp.to_string_lossy();
-                     let path = Path::new(p.trim_start_matches(trim_to_src.as_ref()));
-                     if let Some(stem) = path.file_stem() {
-                         file_map.insert(stem.to_os_string(), (file, path.to_owned()));
-                     }
-                     process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
-                     check_self_named_mod_exists(cx, path, file);
-                 },
-                 _ => {},
++            if let FileName::Real(RealFileName::LocalPath(lp)) = &file.name {
++                let path = if lp.is_relative() {
++                    lp
++                } else if let Ok(relative) = lp.strip_prefix(trim_to_src) {
++                    relative
++                } else {
++                    continue;
++                };
++
++                if let Some(stem) = path.file_stem() {
++                    file_map.insert(stem, (file, path));
++                }
++                process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
++                check_self_named_mod_exists(cx, path, file);
 +            }
 +        }
 +
 +        for folder in &folder_segments {
 +            if !mod_folders.contains(folder) {
 +                if let Some((file, path)) = file_map.get(folder) {
-                     let mut correct = path.clone();
++                    let mut correct = path.to_path_buf();
 +                    correct.pop();
 +                    correct.push(folder);
 +                    correct.push("mod.rs");
 +                    cx.struct_span_lint(
 +                        SELF_NAMED_MODULE_FILES,
 +                        Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
 +                        |build| {
 +                            let mut lint =
 +                                build.build(&format!("`mod.rs` files are required, found `{}`", path.display()));
 +                            lint.help(&format!("move `{}` to `{}`", path.display(), correct.display(),));
 +                            lint.emit();
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// For each `path` we add each folder component to `folder_segments` and if the file name
 +/// is `mod.rs` we add it's parent folder to `mod_folders`.
- fn process_paths_for_mod_files(
-     path: &Path,
-     folder_segments: &mut FxHashSet<OsString>,
-     mod_folders: &mut FxHashSet<OsString>,
++fn process_paths_for_mod_files<'a>(
++    path: &'a Path,
++    folder_segments: &mut FxHashSet<&'a OsStr>,
++    mod_folders: &mut FxHashSet<&'a OsStr>,
 +) {
 +    let mut comp = path.components().rev().peekable();
 +    let _ = comp.next();
 +    if path.ends_with("mod.rs") {
-         mod_folders.insert(comp.peek().map(|c| c.as_os_str().to_owned()).unwrap_or_default());
++        mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
 +    }
-     let folders = comp
-         .filter_map(|c| {
-             if let Component::Normal(s) = c {
-                 Some(s.to_os_string())
-             } else {
-                 None
-             }
-         })
-         .collect::<Vec<_>>();
++    let folders = comp.filter_map(|c| if let Component::Normal(s) = c { Some(s) } else { None });
 +    folder_segments.extend(folders);
 +}
 +
 +/// Checks every path for the presence of `mod.rs` files and emits the lint if found.
 +fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) {
 +    if path.ends_with("mod.rs") {
 +        let mut mod_file = path.to_path_buf();
 +        mod_file.pop();
 +        mod_file.set_extension("rs");
 +
 +        cx.struct_span_lint(
 +            MOD_MODULE_FILES,
 +            Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
 +            |build| {
 +                let mut lint = build.build(&format!("`mod.rs` files are not allowed, found `{}`", path.display()));
 +                lint.help(&format!("move `{}` to `{}`", path.display(), mod_file.display(),));
 +                lint.emit();
 +            },
 +        );
 +    }
 +}
index 6ef6b9a20aa4b185211eaa6c96c48dae49d11af0,0000000000000000000000000000000000000000..2f3007658ea6296f8e2b7b1c541f0224cc10fca0
mode 100644,000000..100644
--- /dev/null
@@@ -1,112 -1,0 +1,116 @@@
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 +use rustc_hir::Expr;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `panic!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// `panic!` will stop the execution of the executable
 +    ///
 +    /// ### Example
 +    /// ```no_run
 +    /// panic!("even with a good reason");
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub PANIC,
 +    restriction,
 +    "usage of the `panic!` macro"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `unimplemented!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This macro should not be present in production code
 +    ///
 +    /// ### Example
 +    /// ```no_run
 +    /// unimplemented!();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub UNIMPLEMENTED,
 +    restriction,
 +    "`unimplemented!` should not be present in production code"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `todo!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This macro should not be present in production code
 +    ///
 +    /// ### Example
 +    /// ```no_run
 +    /// todo!();
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub TODO,
 +    restriction,
 +    "`todo!` should not be present in production code"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `unreachable!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This macro can cause code to panic
 +    ///
 +    /// ### Example
 +    /// ```no_run
 +    /// unreachable!();
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub UNREACHABLE,
 +    restriction,
 +    "usage of the `unreachable!` macro"
 +}
 +
 +declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
 +
 +impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
 +        if is_panic(cx, macro_call.def_id) {
++            if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
++                return;
++            }
++
 +            span_lint(
 +                cx,
 +                PANIC,
 +                macro_call.span,
 +                "`panic` should not be present in production code",
 +            );
 +            return;
 +        }
 +        match cx.tcx.item_name(macro_call.def_id).as_str() {
 +            "todo" => {
 +                span_lint(
 +                    cx,
 +                    TODO,
 +                    macro_call.span,
 +                    "`todo` should not be present in production code",
 +                );
 +            },
 +            "unimplemented" => {
 +                span_lint(
 +                    cx,
 +                    UNIMPLEMENTED,
 +                    macro_call.span,
 +                    "`unimplemented` should not be present in production code",
 +                );
 +            },
 +            "unreachable" => {
 +                span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
 +            },
 +            _ => {},
 +        }
 +    }
 +}
index 5f453dc16555874f783fd6de9d8d54e462b8edb3,0000000000000000000000000000000000000000..48a2666a2e0cef399b2cfeb4a5fd3e808d9b1655
mode 100644,000000..100644
--- /dev/null
@@@ -1,668 -1,0 +1,666 @@@
-                             ty::Adt(def, _)
-                                 if def.did() == args.ty_did =>
-                             {
 +//! Checks for usage of  `&Vec[_]` and `&String`.
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet_opt;
 +use clippy_utils::ty::expr_sig;
 +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
 +use if_chain::if_chain;
 +use rustc_errors::{Applicability, MultiSpan};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::HirIdMap;
 +use rustc_hir::intravisit::{walk_expr, Visitor};
 +use rustc_hir::{
 +    self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArg,
 +    ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
 +    TraitItem, TraitItemKind, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::nested_filter;
 +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;
 +use rustc_span::symbol::Symbol;
 +use std::fmt;
 +use std::iter;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for function arguments of type `&String`, `&Vec`,
 +    /// `&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
 +    /// with the appropriate `.to_owned()`/`to_string()` calls.
 +    ///
 +    /// ### Why is this bad?
 +    /// Requiring the argument to be of the specific size
 +    /// makes the function less useful for no benefit; slices in the form of `&[T]`
 +    /// or `&str` usually suffice and can be obtained from other types, too.
 +    ///
 +    /// ### Known problems
 +    /// There may be `fn(&Vec)`-typed references pointing to your function.
 +    /// If you have them, you will get a compiler error after applying this lint's
 +    /// suggestions. You then have the choice to undo your changes or change the
 +    /// type of the reference.
 +    ///
 +    /// Note that if the function is part of your public interface, there may be
 +    /// other crates referencing it, of which you may not be aware. Carefully
 +    /// deprecate the function before applying the lint suggestions in this case.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// fn foo(&Vec<u32>) { .. }
 +    ///
 +    /// // Good
 +    /// fn foo(&[u32]) { .. }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub PTR_ARG,
 +    style,
 +    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for equality comparisons with `ptr::null`
 +    ///
 +    /// ### Why is this bad?
 +    /// It's easier and more readable to use the inherent
 +    /// `.is_null()`
 +    /// method instead
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// if x == ptr::null {
 +    ///     ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// if x.is_null() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CMP_NULL,
 +    style,
 +    "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for functions that take immutable
 +    /// references and return mutable ones.
 +    ///
 +    /// ### Why is this bad?
 +    /// This is trivially unsound, as one can create two
 +    /// mutable references from the same (immutable!) source.
 +    /// This [error](https://github.com/rust-lang/rust/issues/39465)
 +    /// actually lead to an interim Rust release 1.15.1.
 +    ///
 +    /// ### Known problems
 +    /// To be on the conservative side, if there's at least one
 +    /// mutable reference with the output lifetime, this lint will not trigger.
 +    /// In practice, this case is unlikely anyway.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// fn foo(&Foo) -> &mut Bar { .. }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub MUT_FROM_REF,
 +    correctness,
 +    "fns that create mutable refs from immutable ref args"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for invalid usages of `ptr::null`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This causes undefined behavior.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad. Undefined behavior
 +    /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
 +    /// ```
 +    ///
 +    /// ```ignore
 +    /// // Good
 +    /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
 +    /// ```
 +    #[clippy::version = "1.53.0"]
 +    pub INVALID_NULL_PTR_USAGE,
 +    correctness,
 +    "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead"
 +}
 +
 +declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Ptr {
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if let TraitItemKind::Fn(sig, trait_method) = &item.kind {
 +            if matches!(trait_method, TraitFn::Provided(_)) {
 +                // Handled by check body.
 +                return;
 +            }
 +
 +            check_mut_from_ref(cx, sig.decl);
 +            for arg in check_fn_args(
 +                cx,
 +                cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
 +                sig.decl.inputs,
 +                &[],
 +            )
 +            .filter(|arg| arg.mutability() == Mutability::Not)
 +            {
 +                span_lint_and_sugg(
 +                    cx,
 +                    PTR_ARG,
 +                    arg.span,
 +                    &arg.build_msg(),
 +                    "change this to",
 +                    format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)),
 +                    Applicability::Unspecified,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
 +        let hir = cx.tcx.hir();
 +        let mut parents = hir.parent_iter(body.value.hir_id);
 +        let (item_id, decl, is_trait_item) = match parents.next() {
 +            Some((_, Node::Item(i))) => {
 +                if let ItemKind::Fn(sig, ..) = &i.kind {
 +                    (i.def_id, sig.decl, false)
 +                } else {
 +                    return;
 +                }
 +            },
 +            Some((_, Node::ImplItem(i))) => {
 +                if !matches!(parents.next(),
 +                    Some((_, Node::Item(i))) if matches!(&i.kind, ItemKind::Impl(i) if i.of_trait.is_none())
 +                ) {
 +                    return;
 +                }
 +                if let ImplItemKind::Fn(sig, _) = &i.kind {
 +                    (i.def_id, sig.decl, false)
 +                } else {
 +                    return;
 +                }
 +            },
 +            Some((_, Node::TraitItem(i))) => {
 +                if let TraitItemKind::Fn(sig, _) = &i.kind {
 +                    (i.def_id, sig.decl, true)
 +                } else {
 +                    return;
 +                }
 +            },
 +            _ => return,
 +        };
 +
 +        check_mut_from_ref(cx, decl);
 +        let sig = cx.tcx.fn_sig(item_id).skip_binder();
 +        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
 +            .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
 +            .collect();
 +        let results = check_ptr_arg_usage(cx, body, &lint_args);
 +
 +        for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
 +            span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| {
 +                diag.multipart_suggestion(
 +                    "change this to",
 +                    iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx))))
 +                        .chain(result.replacements.iter().map(|r| {
 +                            (
 +                                r.expr_span,
 +                                format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement),
 +                            )
 +                        }))
 +                        .collect(),
 +                    Applicability::Unspecified,
 +                );
 +            });
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref op, l, r) = expr.kind {
 +            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
 +                span_lint(
 +                    cx,
 +                    CMP_NULL,
 +                    expr.span,
 +                    "comparing with null is better expressed by the `.is_null()` method",
 +                );
 +            }
 +        } else {
 +            check_invalid_ptr_usage(cx, expr);
 +        }
 +    }
 +}
 +
 +fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +    // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
 +    const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 16] = [
 +        (&paths::SLICE_FROM_RAW_PARTS, &[0]),
 +        (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
 +        (&paths::PTR_COPY, &[0, 1]),
 +        (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]),
 +        (&paths::PTR_READ, &[0]),
 +        (&paths::PTR_READ_UNALIGNED, &[0]),
 +        (&paths::PTR_READ_VOLATILE, &[0]),
 +        (&paths::PTR_REPLACE, &[0]),
 +        (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]),
 +        (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
 +        (&paths::PTR_SWAP, &[0, 1]),
 +        (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
 +        (&paths::PTR_WRITE, &[0]),
 +        (&paths::PTR_WRITE_UNALIGNED, &[0]),
 +        (&paths::PTR_WRITE_VOLATILE, &[0]),
 +        (&paths::PTR_WRITE_BYTES, &[0]),
 +    ];
 +
 +    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();
 +        let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
 +        if let Some(&(_, arg_indices)) = INVALID_NULL_PTR_USAGE_TABLE
 +            .iter()
 +            .find(|&&(fn_path, _)| fn_path == fun_def_path);
 +        then {
 +            for &arg_idx in arg_indices {
 +                if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        INVALID_NULL_PTR_USAGE,
 +                        arg.span,
 +                        "pointer must be non-null",
 +                        "change this to",
 +                        "core::ptr::NonNull::dangling().as_ptr()".to_string(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Default)]
 +struct PtrArgResult {
 +    skip: bool,
 +    replacements: Vec<PtrArgReplacement>,
 +}
 +
 +struct PtrArgReplacement {
 +    expr_span: Span,
 +    self_span: Span,
 +    replacement: &'static str,
 +}
 +
 +struct PtrArg<'tcx> {
 +    idx: usize,
 +    span: Span,
 +    ty_did: DefId,
 +    ty_name: Symbol,
 +    method_renames: &'static [(&'static str, &'static str)],
 +    ref_prefix: RefPrefix,
 +    deref_ty: DerefTy<'tcx>,
 +}
 +impl PtrArg<'_> {
 +    fn build_msg(&self) -> String {
 +        format!(
 +            "writing `&{}{}` instead of `&{}{}` involves a new object where a slice will do",
 +            self.ref_prefix.mutability.prefix_str(),
 +            self.ty_name,
 +            self.ref_prefix.mutability.prefix_str(),
 +            self.deref_ty.argless_str(),
 +        )
 +    }
 +
 +    fn mutability(&self) -> Mutability {
 +        self.ref_prefix.mutability
 +    }
 +}
 +
 +struct RefPrefix {
 +    lt: LifetimeName,
 +    mutability: Mutability,
 +}
 +impl fmt::Display for RefPrefix {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        use fmt::Write;
 +        f.write_char('&')?;
 +        match self.lt {
 +            LifetimeName::Param(ParamName::Plain(name)) => {
 +                name.fmt(f)?;
 +                f.write_char(' ')?;
 +            },
 +            LifetimeName::Underscore => f.write_str("'_ ")?,
 +            LifetimeName::Static => f.write_str("'static ")?,
 +            _ => (),
 +        }
 +        f.write_str(self.mutability.prefix_str())
 +    }
 +}
 +
 +struct DerefTyDisplay<'a, 'tcx>(&'a LateContext<'tcx>, &'a DerefTy<'tcx>);
 +impl fmt::Display for DerefTyDisplay<'_, '_> {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        use std::fmt::Write;
 +        match self.1 {
 +            DerefTy::Str => f.write_str("str"),
 +            DerefTy::Path => f.write_str("Path"),
 +            DerefTy::Slice(hir_ty, ty) => {
 +                f.write_char('[')?;
 +                match hir_ty.and_then(|s| snippet_opt(self.0, s)) {
 +                    Some(s) => f.write_str(&s)?,
 +                    None => ty.fmt(f)?,
 +                }
 +                f.write_char(']')
 +            },
 +        }
 +    }
 +}
 +
 +enum DerefTy<'tcx> {
 +    Str,
 +    Path,
 +    Slice(Option<Span>, Ty<'tcx>),
 +}
 +impl<'tcx> DerefTy<'tcx> {
 +    fn argless_str(&self) -> &'static str {
 +        match *self {
 +            Self::Str => "str",
 +            Self::Path => "Path",
 +            Self::Slice(..) => "[_]",
 +        }
 +    }
 +
 +    fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> {
 +        DerefTyDisplay(cx, self)
 +    }
 +}
 +
 +fn check_fn_args<'cx, 'tcx: 'cx>(
 +    cx: &'cx LateContext<'tcx>,
 +    tys: &'tcx [Ty<'_>],
 +    hir_tys: &'tcx [hir::Ty<'_>],
 +    params: &'tcx [Param<'_>],
 +) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx {
 +    tys.iter()
 +        .zip(hir_tys.iter())
 +        .enumerate()
 +        .filter_map(|(i, (ty, hir_ty))| {
 +            if_chain! {
 +                if let ty::Ref(_, ty, mutability) = *ty.kind();
 +                if let ty::Adt(adt, substs) = *ty.kind();
 +
 +                if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
 +                if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
 +
 +                // Check that the name as typed matches the actual name of the type.
 +                // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
 +                if let [.., name] = path.segments;
 +                if cx.tcx.item_name(adt.did()) == name.ident.name;
 +
 +                if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id);
 +                if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id));
 +
 +                then {
 +                    let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
 +                        Some(sym::Vec) => (
 +                            [("clone", ".to_owned()")].as_slice(),
 +                            DerefTy::Slice(
 +                                name.args
 +                                    .and_then(|args| args.args.first())
 +                                    .and_then(|arg| if let GenericArg::Type(ty) = arg {
 +                                        Some(ty.span)
 +                                    } else {
 +                                        None
 +                                    }),
 +                                substs.type_at(0),
 +                            ),
 +                        ),
 +                        Some(sym::String) => (
 +                            [("clone", ".to_owned()"), ("as_str", "")].as_slice(),
 +                            DerefTy::Str,
 +                        ),
 +                        Some(sym::PathBuf) => (
 +                            [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(),
 +                            DerefTy::Path,
 +                        ),
 +                        Some(sym::Cow) if mutability == Mutability::Not => {
 +                            let ty_name = name.args
 +                                .and_then(|args| {
 +                                    args.args.iter().find_map(|a| match a {
 +                                        GenericArg::Type(x) => Some(x),
 +                                        _ => None,
 +                                    })
 +                                })
 +                                .and_then(|arg| snippet_opt(cx, arg.span))
 +                                .unwrap_or_else(|| substs.type_at(1).to_string());
 +                            span_lint_and_sugg(
 +                                cx,
 +                                PTR_ARG,
 +                                hir_ty.span,
 +                                "using a reference to `Cow` is not recommended",
 +                                "change this to",
 +                                format!("&{}{}", mutability.prefix_str(), ty_name),
 +                                Applicability::Unspecified,
 +                            );
 +                            return None;
 +                        },
 +                        _ => return None,
 +                    };
 +                    return Some(PtrArg {
 +                        idx: i,
 +                        span: hir_ty.span,
 +                        ty_did: adt.did(),
 +                        ty_name: name.ident.name,
 +                        method_renames,
 +                        ref_prefix: RefPrefix {
 +                            lt: lt.name,
 +                            mutability,
 +                        },
 +                        deref_ty,
 +                    });
 +                }
 +            }
 +            None
 +        })
 +}
 +
 +fn check_mut_from_ref(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
 +    if let FnRetTy::Return(ty) = decl.output {
 +        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
 +            let mut immutables = vec![];
 +            for (_, mutbl, argspan) in decl
 +                .inputs
 +                .iter()
 +                .filter_map(get_rptr_lm)
 +                .filter(|&(lt, _, _)| lt.name == out.name)
 +            {
 +                if mutbl == Mutability::Mut {
 +                    return;
 +                }
 +                immutables.push(argspan);
 +            }
 +            if immutables.is_empty() {
 +                return;
 +            }
 +            span_lint_and_then(
 +                cx,
 +                MUT_FROM_REF,
 +                ty.span,
 +                "mutable borrow from immutable input(s)",
 +                |diag| {
 +                    let ms = MultiSpan::from_spans(immutables);
 +                    diag.span_note(ms, "immutable borrow here");
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
 +    struct V<'cx, 'tcx> {
 +        cx: &'cx LateContext<'tcx>,
 +        /// Map from a local id to which argument it came from (index into `Self::args` and
 +        /// `Self::results`)
 +        bindings: HirIdMap<usize>,
 +        /// The arguments being checked.
 +        args: &'cx [PtrArg<'tcx>],
 +        /// The results for each argument (len should match args.len)
 +        results: Vec<PtrArgResult>,
 +        /// The number of arguments which can't be linted. Used to return early.
 +        skip_count: usize,
 +    }
 +    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
 +        type NestedFilter = nested_filter::OnlyBodies;
 +        fn nested_visit_map(&mut self) -> Self::Map {
 +            self.cx.tcx.hir()
 +        }
 +
 +        fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
 +
 +        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +            if self.skip_count == self.args.len() {
 +                return;
 +            }
 +
 +            // Check if this is local we care about
 +            let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
 +                Some(&i) => i,
 +                None => return walk_expr(self, e),
 +            };
 +            let args = &self.args[args_idx];
 +            let result = &mut self.results[args_idx];
 +
 +            // Helper function to handle early returns.
 +            let mut set_skip_flag = || {
 +                if !result.skip {
 +                    self.skip_count += 1;
 +                }
 +                result.skip = true;
 +            };
 +
 +            match get_expr_use_or_unification_node(self.cx.tcx, e) {
 +                Some((Node::Stmt(_), _)) => (),
 +                Some((Node::Local(l), _)) => {
 +                    // Only trace simple bindings. e.g `let x = y;`
 +                    if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
 +                        self.bindings.insert(id, args_idx);
 +                    } else {
 +                        set_skip_flag();
 +                    }
 +                },
 +                Some((Node::Expr(e), child_id)) => match e.kind {
 +                    ExprKind::Call(f, expr_args) => {
 +                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
 +                        if expr_sig(self.cx, f)
 +                            .map(|sig| sig.input(i).skip_binder().peel_refs())
 +                            .map_or(true, |ty| match *ty.kind() {
 +                                ty::Param(_) => true,
 +                                ty::Adt(def, _) => def.did() == args.ty_did,
 +                                _ => false,
 +                            })
 +                        {
 +                            // Passed to a function taking the non-dereferenced type.
 +                            set_skip_flag();
 +                        }
 +                    },
 +                    ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
 +                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
 +                        if i == 0 {
 +                            // Check if the method can be renamed.
 +                            let name = name.ident.as_str();
 +                            if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
 +                                result.replacements.push(PtrArgReplacement {
 +                                    expr_span: e.span,
 +                                    self_span: self_arg.span,
 +                                    replacement,
 +                                });
 +                                return;
 +                            }
 +                        }
 +
 +                        let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
 +                            x
 +                        } else {
 +                            set_skip_flag();
 +                            return;
 +                        };
 +
 +                        match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
 +                            ty::Param(_) => {
 +                                set_skip_flag();
 +                            },
 +                            // If the types match check for methods which exist on both types. e.g. `Vec::len` and
 +                            // `slice::len`
++                            ty::Adt(def, _) if def.did() == args.ty_did => {
 +                                set_skip_flag();
 +                            },
 +                            _ => (),
 +                        }
 +                    },
 +                    // Indexing is fine for currently supported types.
 +                    ExprKind::Index(e, _) if e.hir_id == child_id => (),
 +                    _ => set_skip_flag(),
 +                },
 +                _ => set_skip_flag(),
 +            }
 +        }
 +    }
 +
 +    let mut skip_count = 0;
 +    let mut results = args.iter().map(|_| PtrArgResult::default()).collect::<Vec<_>>();
 +    let mut v = V {
 +        cx,
 +        bindings: args
 +            .iter()
 +            .enumerate()
 +            .filter_map(|(i, arg)| {
 +                let param = &body.params[arg.idx];
 +                match param.pat.kind {
 +                    PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
 +                        if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
 +                    {
 +                        Some((id, i))
 +                    },
 +                    _ => {
 +                        skip_count += 1;
 +                        results[i].skip = true;
 +                        None
 +                    },
 +                }
 +            })
 +            .collect(),
 +        args,
 +        results,
 +        skip_count,
 +    };
 +    v.visit_expr(&body.value);
 +    v.results
 +}
 +
 +fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
 +    if let TyKind::Rptr(ref lt, ref m) = ty.kind {
 +        Some((lt, m.mutbl, ty.span))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(pathexp, []) = expr.kind {
 +        path_def_id(cx, pathexp).map_or(false, |id| {
 +            matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))
 +        })
 +    } else {
 +        false
 +    }
 +}
index 02569bd3a476e50e3b0ea759ad9930712847f481,0000000000000000000000000000000000000000..342f23f030cd06fa3bf3c55355f50f92c2ede39e
mode 100644,000000..100644
--- /dev/null
@@@ -1,448 -1,0 +1,449 @@@
-                 // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts.
-                 // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`.
-                 // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
 +mod crosspointer_transmute;
 +mod transmute_float_to_int;
 +mod transmute_int_to_bool;
 +mod transmute_int_to_char;
 +mod transmute_int_to_float;
 +mod transmute_num_to_bytes;
 +mod transmute_ptr_to_ptr;
 +mod transmute_ptr_to_ref;
 +mod transmute_ref_to_ref;
 +mod transmute_undefined_repr;
 +mod transmutes_expressible_as_ptr_casts;
 +mod unsound_collection_transmute;
 +mod useless_transmute;
 +mod utils;
 +mod wrong_transmute;
 +
 +use clippy_utils::in_constant;
 +use if_chain::if_chain;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes that can't ever be correct on any
 +    /// architecture.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's basically guaranteed to be undefined behaviour.
 +    ///
 +    /// ### Known problems
 +    /// When accessing C, users might want to store pointer
 +    /// sized objects in `extradata` arguments to save an allocation.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// let ptr: *const T = core::intrinsics::transmute('x')
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub WRONG_TRANSMUTE,
 +    correctness,
 +    "transmutes that are confusing at best, undefined behaviour at worst and always useless"
 +}
 +
 +// FIXME: Move this to `complexity` again, after #5343 is fixed
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes to the original type of the object
 +    /// and transmutes that could be a cast.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability. The code tricks people into thinking that
 +    /// something complex is going on.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USELESS_TRANSMUTE,
 +    nursery,
 +    "transmutes that have the same to and from types or could be a cast/coercion"
 +}
 +
 +// FIXME: Merge this lint with USELESS_TRANSMUTE once that is out of the nursery.
 +declare_clippy_lint! {
 +    /// ### What it does
 +    ///Checks for transmutes that could be a pointer cast.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability. The code tricks people into thinking that
 +    /// something complex is going on.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```rust
 +    /// # let p: *const [i32] = &[];
 +    /// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let p: *const [i32] = &[];
 +    /// p as *const [u16];
 +    /// ```
 +    #[clippy::version = "1.47.0"]
 +    pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    complexity,
 +    "transmutes that could be a pointer cast"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes between a type `T` and `*T`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's easy to mistakenly transmute between a type and a
 +    /// pointer to that type.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// core::intrinsics::transmute(t) // where the result type is the same as
 +    ///                                // `*t` or `&t`'s
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub CROSSPOINTER_TRANSMUTE,
 +    complexity,
 +    "transmutes that have to or from types that are a pointer to the other"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from a pointer to a reference.
 +    ///
 +    /// ### Why is this bad?
 +    /// This can always be rewritten with `&` and `*`.
 +    ///
 +    /// ### Known problems
 +    /// - `mem::transmute` in statics and constants is stable from Rust 1.46.0,
 +    /// while dereferencing raw pointer is not stable yet.
 +    /// If you need to do this in those places,
 +    /// you would have to use `transmute` instead.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// unsafe {
 +    ///     let _: &T = std::mem::transmute(p); // where p: *const T
 +    /// }
 +    ///
 +    /// // can be written:
 +    /// let _: &T = &*p;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_PTR_TO_REF,
 +    complexity,
 +    "transmutes from a pointer to a reference type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from an integer to a `char`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not every integer is a Unicode scalar value.
 +    ///
 +    /// ### Known problems
 +    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
 +    /// as it needs to validate the input.
 +    /// If you are certain that the input is always a valid Unicode scalar value,
 +    /// use [`from_u32_unchecked`] which is as fast as `transmute`
 +    /// but has a semantically meaningful name.
 +    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
 +    ///
 +    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
 +    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 1_u32;
 +    /// unsafe {
 +    ///     let _: char = std::mem::transmute(x); // where x: u32
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _ = std::char::from_u32(x).unwrap();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_INT_TO_CHAR,
 +    complexity,
 +    "transmutes from an integer to a `char`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from a `&[u8]` to a `&str`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Not every byte slice is a valid UTF-8 string.
 +    ///
 +    /// ### Known problems
 +    /// - [`from_utf8`] which this lint suggests using is slower than `transmute`
 +    /// as it needs to validate the input.
 +    /// If you are certain that the input is always a valid UTF-8,
 +    /// use [`from_utf8_unchecked`] which is as fast as `transmute`
 +    /// but has a semantically meaningful name.
 +    /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
 +    ///
 +    /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
 +    /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let b: &[u8] = &[1_u8, 2_u8];
 +    /// unsafe {
 +    ///     let _: &str = std::mem::transmute(b); // where b: &[u8]
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _ = std::str::from_utf8(b).unwrap();
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_BYTES_TO_STR,
 +    complexity,
 +    "transmutes from a `&[u8]` to a `&str`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from an integer to a `bool`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This might result in an invalid in-memory representation of a `bool`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 1_u8;
 +    /// unsafe {
 +    ///     let _: bool = std::mem::transmute(x); // where x: u8
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: bool = x != 0;
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_INT_TO_BOOL,
 +    complexity,
 +    "transmutes from an integer to a `bool`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from an integer to a float.
 +    ///
 +    /// ### Why is this bad?
 +    /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
 +    /// and safe.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// unsafe {
 +    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: f32 = f32::from_bits(1_u32);
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_INT_TO_FLOAT,
 +    complexity,
 +    "transmutes from an integer to a float"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from a float to an integer.
 +    ///
 +    /// ### Why is this bad?
 +    /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
 +    /// and safe.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// unsafe {
 +    ///     let _: u32 = std::mem::transmute(1f32);
 +    /// }
 +    ///
 +    /// // should be:
 +    /// let _: u32 = 1f32.to_bits();
 +    /// ```
 +    #[clippy::version = "1.41.0"]
 +    pub TRANSMUTE_FLOAT_TO_INT,
 +    complexity,
 +    "transmutes from a float to an integer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from a number to an array of `u8`
 +    ///
 +    /// ### Why this is bad?
 +    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
 +    /// is intuitive and safe.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// unsafe {
 +    ///     let x: [u8; 8] = std::mem::transmute(1i64);
 +    /// }
 +    ///
 +    /// // should be
 +    /// let x: [u8; 8] = 0i64.to_ne_bytes();
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub TRANSMUTE_NUM_TO_BYTES,
 +    complexity,
 +    "transmutes from a number to an array of `u8`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes from a pointer to a pointer, or
 +    /// from a reference to a reference.
 +    ///
 +    /// ### Why is this bad?
 +    /// Transmutes are dangerous, and these can instead be
 +    /// written as casts.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let ptr = &1u32 as *const u32;
 +    /// unsafe {
 +    ///     // pointer-to-pointer transmute
 +    ///     let _: *const f32 = std::mem::transmute(ptr);
 +    ///     // ref-ref transmute
 +    ///     let _: &f32 = std::mem::transmute(&1u32);
 +    /// }
 +    /// // These can be respectively written:
 +    /// let _ = ptr as *const f32;
 +    /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub TRANSMUTE_PTR_TO_PTR,
 +    pedantic,
 +    "transmutes from a pointer to a pointer / a reference to a reference"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes between collections whose
 +    /// types have different ABI, size or alignment.
 +    ///
 +    /// ### Why is this bad?
 +    /// This is undefined behavior.
 +    ///
 +    /// ### Known problems
 +    /// Currently, we cannot know whether a type is a
 +    /// collection, so we just lint the ones that come with `std`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // different size, therefore likely out-of-bounds memory access
 +    /// // You absolutely do not want this in your code!
 +    /// unsafe {
 +    ///     std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
 +    /// };
 +    /// ```
 +    ///
 +    /// You must always iterate, map and collect the values:
 +    ///
 +    /// ```rust
 +    /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
 +    /// ```
 +    #[clippy::version = "1.40.0"]
 +    pub UNSOUND_COLLECTION_TRANSMUTE,
 +    correctness,
 +    "transmute between collections of layout-incompatible types"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for transmutes between types which do not have a representation defined relative to
 +    /// each other.
 +    ///
 +    /// ### Why is this bad?
 +    /// The results of such a transmute are not defined.
 +    ///
 +    /// ### Known problems
 +    /// This lint has had multiple problems in the past and was moved to `nursery`. See issue
 +    /// [#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// struct Foo<T>(u32, T);
 +    /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// #[repr(C)]
 +    /// struct Foo<T>(u32, T);
 +    /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
 +    /// ```
 +    #[clippy::version = "1.60.0"]
 +    pub TRANSMUTE_UNDEFINED_REPR,
 +    nursery,
 +    "transmute to or from a type with an undefined representation"
 +}
 +
 +declare_lint_pass!(Transmute => [
 +    CROSSPOINTER_TRANSMUTE,
 +    TRANSMUTE_PTR_TO_REF,
 +    TRANSMUTE_PTR_TO_PTR,
 +    USELESS_TRANSMUTE,
 +    WRONG_TRANSMUTE,
 +    TRANSMUTE_INT_TO_CHAR,
 +    TRANSMUTE_BYTES_TO_STR,
 +    TRANSMUTE_INT_TO_BOOL,
 +    TRANSMUTE_INT_TO_FLOAT,
 +    TRANSMUTE_FLOAT_TO_INT,
 +    TRANSMUTE_NUM_TO_BYTES,
 +    UNSOUND_COLLECTION_TRANSMUTE,
 +    TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    TRANSMUTE_UNDEFINED_REPR,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Transmute {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(path_expr, [arg]) = e.kind;
 +            if let ExprKind::Path(ref qpath) = path_expr.kind;
 +            if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
 +            if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
 +            then {
-                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg)
++                // Avoid suggesting non-const operations in const contexts:
++                // - from/to bits (https://github.com/rust-lang/rust/issues/73736)
++                // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911)
++                // - char conversions (https://github.com/rust-lang/rust/issues/89259)
 +                let const_context = in_constant(cx, e.hir_id);
 +
 +                let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
 +                // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
 +                let to_ty = cx.typeck_results().expr_ty(e);
 +
 +                // If useless_transmute is triggered, the other lints can be skipped.
 +                if useless_transmute::check(cx, e, from_ty, to_ty, arg) {
 +                    return;
 +                }
 +
 +                let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
 +                    | crosspointer_transmute::check(cx, e, from_ty, to_ty)
 +                    | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, qpath)
++                    | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
 +                    | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
 +                    | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
 +                    | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
 +                    | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
 +                    | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
 +                    | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
 +                    | (
 +                        unsound_collection_transmute::check(cx, e, from_ty, to_ty)
 +                        || transmute_undefined_repr::check(cx, e, from_ty, to_ty)
 +                    );
 +
 +                if !linted {
 +                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
 +                }
 +            }
 +        }
 +    }
 +}
index 3eb07b68992a89b96ff10c4a40277023c8878536,0000000000000000000000000000000000000000..9e1823c373bfdb4d641536bfd04b10157eda1b1c
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,46 @@@
-         (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) => {
 +use super::TRANSMUTE_INT_TO_CHAR;
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::sugg;
 +use rustc_ast as ast;
 +use rustc_errors::Applicability;
 +use rustc_hir::Expr;
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, Ty};
 +
 +/// Checks for `transmute_int_to_char` lint.
 +/// Returns `true` if it's triggered, otherwise returns `false`.
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    from_ty: Ty<'tcx>,
 +    to_ty: Ty<'tcx>,
 +    arg: &'tcx Expr<'_>,
++    const_context: bool,
 +) -> bool {
 +    match (&from_ty.kind(), &to_ty.kind()) {
++        (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) if !const_context => {
 +            span_lint_and_then(
 +                cx,
 +                TRANSMUTE_INT_TO_CHAR,
 +                e.span,
 +                &format!("transmute from a `{}` to a `char`", from_ty),
 +                |diag| {
 +                    let arg = sugg::Sugg::hir(cx, arg, "..");
 +                    let arg = if let ty::Int(_) = from_ty.kind() {
 +                        arg.as_ty(ast::UintTy::U32.name_str())
 +                    } else {
 +                        arg
 +                    };
 +                    diag.span_suggestion(
 +                        e.span,
 +                        "consider using",
 +                        format!("std::char::from_u32({}).unwrap()", arg),
 +                        Applicability::Unspecified,
 +                    );
 +                },
 +            );
 +            true
 +        },
 +        _ => false,
 +    }
 +}
index 7570bc2a7a8f0d8195e2f8d560f29f36a06c97b3,0000000000000000000000000000000000000000..786e7bfc56f6ecbb00e442e72bd530f865d26100
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,89 @@@
-                     format!(
-                         "std::str::from_utf8{}({}).unwrap()",
-                         postfix,
-                         snippet(cx, arg.span, ".."),
-                     ),
-                     Applicability::Unspecified,
 +use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR};
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::source::snippet;
 +use clippy_utils::sugg;
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, Mutability};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, Ty};
 +
 +/// Checks for `transmute_bytes_to_str` and `transmute_ptr_to_ptr` lints.
 +/// Returns `true` if either one triggered, otherwise returns `false`.
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    e: &'tcx Expr<'_>,
 +    from_ty: Ty<'tcx>,
 +    to_ty: Ty<'tcx>,
 +    arg: &'tcx Expr<'_>,
 +    const_context: bool,
 +) -> bool {
 +    let mut triggered = false;
 +
 +    if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) {
 +        if_chain! {
 +            if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind());
 +            if let ty::Uint(ty::UintTy::U8) = slice_ty.kind();
 +            if from_mutbl == to_mutbl;
 +            then {
 +                let postfix = if *from_mutbl == Mutability::Mut {
 +                    "_mut"
 +                } else {
 +                    ""
 +                };
 +
++                let snippet = snippet(cx, arg.span, "..");
++
 +                span_lint_and_sugg(
 +                    cx,
 +                    TRANSMUTE_BYTES_TO_STR,
 +                    e.span,
 +                    &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
 +                    "consider using",
++                    if const_context {
++                        format!("std::str::from_utf8_unchecked{postfix}({snippet})")
++                    } else {
++                        format!("std::str::from_utf8{postfix}({snippet}).unwrap()")
++                    },
++                    Applicability::MaybeIncorrect,
 +                );
 +                triggered = true;
 +            } else {
 +                if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty))
 +                    && !const_context {
 +                    span_lint_and_then(
 +                        cx,
 +                        TRANSMUTE_PTR_TO_PTR,
 +                        e.span,
 +                        "transmute from a reference to a reference",
 +                        |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
 +                            let ty_from_and_mut = ty::TypeAndMut {
 +                                ty: *ty_from,
 +                                mutbl: *from_mutbl
 +                            };
 +                            let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl };
 +                            let sugg_paren = arg
 +                                .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
 +                                .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
 +                            let sugg = if *to_mutbl == Mutability::Mut {
 +                                sugg_paren.mut_addr_deref()
 +                            } else {
 +                                sugg_paren.addr_deref()
 +                            };
 +                            diag.span_suggestion(
 +                                e.span,
 +                                "try",
 +                                sugg.to_string(),
 +                                Applicability::Unspecified,
 +                            );
 +                        },
 +                    );
 +
 +                    triggered = true;
 +                }
 +            }
 +        }
 +    }
 +
 +    triggered
 +}
index e42c6c63ede0ba2e419de335318e2bcf841d4a89,0000000000000000000000000000000000000000..c8912a18f1854e3dcf5ee2252b1dcb52ced5d754
mode 100644,000000..100644
--- /dev/null
@@@ -1,222 -1,0 +1,197 @@@
- use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
++use clippy_utils::diagnostics::span_lint_and_help;
 +use clippy_utils::is_lint_allowed;
- use clippy_utils::source::{indent_of, reindent_multiline, snippet};
- use rustc_errors::Applicability;
- use rustc_hir::intravisit::{walk_expr, Visitor};
- use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
- use rustc_lexer::TokenKind;
- use rustc_lint::{LateContext, LateLintPass};
++use clippy_utils::source::walk_span_to_context;
++use rustc_data_structures::sync::Lrc;
++use rustc_hir::{Block, BlockCheckMode, UnsafeSource};
++use rustc_lexer::{tokenize, TokenKind};
++use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
- use rustc_middle::ty::TyCtxt;
- use rustc_session::{declare_tool_lint, impl_lint_pass};
- use rustc_span::{BytePos, Span};
- use std::borrow::Cow;
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::{BytePos, Pos, SyntaxContext};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `unsafe` blocks without a `// SAFETY: ` comment
 +    /// explaining why the unsafe operations performed inside
 +    /// the block are safe.
 +    ///
++    /// Note the comment must appear on the line(s) preceding the unsafe block
++    /// with nothing appearing in between. The following is ok:
++    /// ```ignore
++    /// foo(
++    ///     // SAFETY:
++    ///     // This is a valid safety comment
++    ///     unsafe { *x }
++    /// )
++    /// ```
++    /// But neither of these are:
++    /// ```ignore
++    /// // SAFETY:
++    /// // This is not a valid safety comment
++    /// foo(
++    ///     /* SAFETY: Neither is this */ unsafe { *x },
++    /// );
++    /// ```
++    ///
 +    /// ### Why is this bad?
 +    /// Undocumented unsafe blocks can make it difficult to
 +    /// read and maintain code, as well as uncover unsoundness
 +    /// and bugs.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
 +    /// // SAFETY: references are guaranteed to be non-null.
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    #[clippy::version = "1.58.0"]
 +    pub UNDOCUMENTED_UNSAFE_BLOCKS,
 +    restriction,
 +    "creating an unsafe block without explaining why it is safe"
 +}
 +
- impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
- #[derive(Default)]
- pub struct UndocumentedUnsafeBlocks {
-     pub local_level: u32,
-     pub local_span: Option<Span>,
-     // The local was already checked for an overall safety comment
-     // There is no need to continue checking the blocks in the local
-     pub local_checked: bool,
-     // Since we can only check the blocks from expanded macros
-     // We have to omit the suggestion due to the actual definition
-     // Not being available to us
-     pub macro_expansion: bool,
- }
++declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
 +
 +impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
 +    fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
-         if_chain! {
-             if !self.local_checked;
-             if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
-             if !in_external_macro(cx.tcx.sess, block.span);
-             if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
-             if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
-             if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
-             then {
-                 let mut span = block.span;
-                 if let Some(local_span) = self.local_span {
-                     span = local_span;
-                     let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
++        if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
++            && !in_external_macro(cx.tcx.sess, block.span)
++            && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
++            && !is_unsafe_from_proc_macro(cx, block)
++            && !block_has_safety_comment(cx, block)
++        {
++            let source_map = cx.tcx.sess.source_map();
++            let span = if source_map.is_multiline(block.span) {
++                source_map.span_until_char(block.span, '\n')
++            } else {
++                block.span
++            };
 +
-                     if result.unwrap_or(true) {
-                         self.local_checked = true;
-                         return;
-                     }
-                 }
-                 self.lint(cx, span);
-             }
-         }
-     }
-     fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
-         if_chain! {
-             if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
-             if !in_external_macro(cx.tcx.sess, local.span);
-             if let Some(init) = local.init;
-             then {
-                 self.visit_expr(init);
-                 if self.local_level > 0 {
-                     self.local_span = Some(local.span);
-                 }
-             }
++            span_lint_and_help(
++                cx,
++                UNDOCUMENTED_UNSAFE_BLOCKS,
++                span,
++                "unsafe block missing a safety comment",
++                None,
++                "consider adding a safety comment on the preceding line",
++            );
 +        }
 +    }
++}
 +
-     fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
-         self.local_level = self.local_level.saturating_sub(1);
-         if self.local_level == 0 {
-             self.local_checked = false;
-             self.local_span = None;
-         }
-     }
++fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
++    let source_map = cx.sess().source_map();
++    let file_pos = source_map.lookup_byte_offset(block.span.lo());
++    file_pos
++        .sf
++        .src
++        .as_deref()
++        .and_then(|src| src.get(file_pos.pos.to_usize()..))
++        .map_or(true, |src| !src.starts_with("unsafe"))
 +}
 +
- impl<'v> Visitor<'v> for UndocumentedUnsafeBlocks {
-     fn visit_expr(&mut self, ex: &'v Expr<'v>) {
-         match ex.kind {
-             ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
-             _ => walk_expr(self, ex),
++/// Checks if the lines immediately preceding the block contain a safety comment.
++fn block_has_safety_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
++    // This intentionally ignores text before the start of a function so something like:
++    // ```
++    //     // SAFETY: reason
++    //     fn foo() { unsafe { .. } }
++    // ```
++    // won't work. This is to avoid dealing with where such a comment should be place relative to
++    // attributes and doc comments.
++
++    let source_map = cx.sess().source_map();
++    let ctxt = block.span.ctxt();
++    if ctxt != SyntaxContext::root() {
++        // From a macro expansion. Get the text from the start of the macro declaration to start of the unsafe block.
++        //     macro_rules! foo { () => { stuff }; (x) => { unsafe { stuff } }; }
++        //     ^--------------------------------------------^
++        if let Ok(unsafe_line) = source_map.lookup_line(block.span.lo())
++            && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
++            && Lrc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
++            && let Some(src) = unsafe_line.sf.src.as_deref()
++        {
++            macro_line.line < unsafe_line.line && text_has_safety_comment(
++                src,
++                &unsafe_line.sf.lines[macro_line.line + 1..=unsafe_line.line],
++                unsafe_line.sf.start_pos.to_usize(),
++            )
++        } else {
++            // Problem getting source text. Pretend a comment was found.
++            true
 +        }
++    } else if let Ok(unsafe_line) = source_map.lookup_line(block.span.lo())
++        && let Some(body) = cx.enclosing_body
++        && let Some(body_span) = walk_span_to_context(cx.tcx.hir().body(body).value.span, SyntaxContext::root())
++        && let Ok(body_line) = source_map.lookup_line(body_span.lo())
++        && Lrc::ptr_eq(&unsafe_line.sf, &body_line.sf)
++        && let Some(src) = unsafe_line.sf.src.as_deref()
++    {
++        // Get the text from the start of function body to the unsafe block.
++        //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
++        //              ^-------------^
++        body_line.line < unsafe_line.line && text_has_safety_comment(
++            src,
++            &unsafe_line.sf.lines[body_line.line + 1..=unsafe_line.line],
++            unsafe_line.sf.start_pos.to_usize(),
++        )
++    } else {
++        // Problem getting source text. Pretend a comment was found.
++        true
 +    }
 +}
 +
- impl UndocumentedUnsafeBlocks {
-     fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
-         let map = tcx.hir();
-         let source_map = tcx.sess.source_map();
-         let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
-         let between_span = if block_span.from_expansion() {
-             self.macro_expansion = true;
-             enclosing_scope_span.with_hi(block_span.hi()).source_callsite()
-         } else {
-             self.macro_expansion = false;
-             enclosing_scope_span.to(block_span).source_callsite()
-         };
-         let file_name = source_map.span_to_filename(between_span);
-         let source_file = source_map.get_source_file(&file_name)?;
-         let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
-         let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
-         let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
-         let source_start_pos = source_file.start_pos.0 as usize + lex_start;
-         let mut pos = 0;
-         let mut comment = false;
-         for token in rustc_lexer::tokenize(&src_str) {
-             match token.kind {
-                 TokenKind::LineComment { doc_style: None }
-                 | TokenKind::BlockComment {
-                     doc_style: None,
-                     terminated: true,
-                 } => {
-                     let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
-                     if comment_str.contains("SAFETY:") {
-                         comment = true;
-                     }
-                 },
-                 // We need to add all whitespace to `pos` before checking the comment's line number
-                 TokenKind::Whitespace => {},
-                 _ => {
-                     if comment {
-                         // Get the line number of the "comment" (really wherever the trailing whitespace ended)
-                         let comment_line_num = source_file
-                             .lookup_file_pos(BytePos((source_start_pos + pos).try_into().unwrap()))
-                             .0;
-                         // Find the block/local's line number
-                         let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
-                         // Check the comment is immediately followed by the block/local
-                         if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
-                             return Some(true);
-                         }
-                         comment = false;
-                     }
-                 },
++/// Checks if the given text has a safety comment for the immediately proceeding line.
++fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> bool {
++    let mut lines = line_starts
++        .array_windows::<2>()
++        .rev()
++        .map_while(|[start, end]| {
++            src.get(start.to_usize() - offset..end.to_usize() - offset)
++                .map(|text| (start.to_usize(), text.trim_start()))
++        })
++        .filter(|(_, text)| !text.is_empty());
++
++    let Some((line_start, line)) = lines.next() else {
++        return false;
++    };
++    // Check for a sequence of line comments.
++    if line.starts_with("//") {
++        let mut line = line;
++        loop {
++            if line.to_ascii_uppercase().contains("SAFETY:") {
++                return true;
++            }
++            match lines.next() {
++                Some((_, x)) if x.starts_with("//") => line = x,
++                _ => return false,
 +            }
-             pos += token.len;
 +        }
-         Some(false)
 +    }
-     fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
-         let source_map = cx.tcx.sess.source_map();
-         if source_map.is_multiline(span) {
-             span = source_map.span_until_char(span, '\n');
++    // No line comments; look for the start of a block comment.
++    // This will only find them if they are at the start of a line.
++    let (mut line_start, mut line) = (line_start, line);
++    loop {
++        if line.starts_with("/*") {
++            let src = src[line_start..line_starts.last().unwrap().to_usize()].trim_start();
++            let mut tokens = tokenize(src);
++            return src[..tokens.next().unwrap().len]
++                .to_ascii_uppercase()
++                .contains("SAFETY:")
++                && tokens.all(|t| t.kind == TokenKind::Whitespace);
 +        }
-         if self.macro_expansion {
-             span_lint_and_help(
-                 cx,
-                 UNDOCUMENTED_UNSAFE_BLOCKS,
-                 span,
-                 "unsafe block in macro expansion missing a safety comment",
-                 None,
-                 "consider adding a safety comment in the macro definition",
-             );
-         } else {
-             let block_indent = indent_of(cx, span);
-             let suggestion = format!("// SAFETY: ...\n{}", snippet(cx, span, ".."));
-             span_lint_and_sugg(
-                 cx,
-                 UNDOCUMENTED_UNSAFE_BLOCKS,
-                 span,
-                 "unsafe block missing a safety comment",
-                 "consider adding a safety comment",
-                 reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
-                 Applicability::HasPlaceholders,
-             );
++        match lines.next() {
++            Some(x) => (line_start, line) = x,
++            None => return false,
 +        }
 +    }
 +}
index 09d671e11184d6e2e456909b3326af74b6ce3c04,0000000000000000000000000000000000000000..f8e1021af0ea11b9bd46acc78dfe62ea9ea4ccaf
mode 100644,000000..100644
--- /dev/null
@@@ -1,312 -1,0 +1,312 @@@
-     /// struct Foo {}
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::ty::same_type_and_consts;
 +use clippy_utils::{meets_msrv, msrvs};
 +use if_chain::if_chain;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    self as hir,
 +    def::{CtorOf, DefKind, Res},
 +    def_id::LocalDefId,
 +    intravisit::{walk_inf, walk_ty, Visitor},
 +    Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath,
 +    TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::Span;
 +use rustc_typeck::hir_ty_to_ty;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary repetition of structure name when a
 +    /// replacement with `Self` is applicable.
 +    ///
 +    /// ### Why is this bad?
 +    /// Unnecessary repetition. Mixed use of `Self` and struct
 +    /// name
 +    /// feels inconsistent.
 +    ///
 +    /// ### Known problems
 +    /// - Unaddressed false negative in fn bodies of trait implementations
 +    /// - False positive with assotiated types in traits (#4140)
 +    ///
 +    /// ### Example
 +    /// ```rust
-     /// struct Foo {}
++    /// struct Foo;
 +    /// impl Foo {
 +    ///     fn new() -> Foo {
 +    ///         Foo {}
 +    ///     }
 +    /// }
 +    /// ```
 +    /// could be
 +    /// ```rust
++    /// struct Foo;
 +    /// impl Foo {
 +    ///     fn new() -> Self {
 +    ///         Self {}
 +    ///     }
 +    /// }
 +    /// ```
 +    #[clippy::version = "pre 1.29.0"]
 +    pub USE_SELF,
 +    nursery,
 +    "unnecessary structure name repetition whereas `Self` is applicable"
 +}
 +
 +#[derive(Default)]
 +pub struct UseSelf {
 +    msrv: Option<RustcVersion>,
 +    stack: Vec<StackItem>,
 +}
 +
 +impl UseSelf {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            msrv,
 +            ..Self::default()
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +enum StackItem {
 +    Check {
 +        impl_id: LocalDefId,
 +        in_body: u32,
 +        types_to_skip: FxHashSet<HirId>,
 +    },
 +    NoCheck,
 +}
 +
 +impl_lint_pass!(UseSelf => [USE_SELF]);
 +
 +const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 +
 +impl<'tcx> LateLintPass<'tcx> for UseSelf {
 +    fn check_item(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
 +        if matches!(item.kind, ItemKind::OpaqueTy(_)) {
 +            // skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
 +            return;
 +        }
 +        // We push the self types of `impl`s on a stack here. Only the top type on the stack is
 +        // relevant for linting, since this is the self type of the `impl` we're currently in. To
 +        // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
 +        // we're in an `impl` or nested item, that we don't want to lint
 +        let stack_item = if_chain! {
 +            if let ItemKind::Impl(Impl { self_ty, .. }) = item.kind;
 +            if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind;
 +            let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
 +            if parameters.as_ref().map_or(true, |params| {
 +                !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
 +            });
 +            then {
 +                StackItem::Check {
 +                    impl_id: item.def_id,
 +                    in_body: 0,
 +                    types_to_skip: std::iter::once(self_ty.hir_id).collect(),
 +                }
 +            } else {
 +                StackItem::NoCheck
 +            }
 +        };
 +        self.stack.push(stack_item);
 +    }
 +
 +    fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
 +        if !matches!(item.kind, ItemKind::OpaqueTy(_)) {
 +            self.stack.pop();
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
 +        // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
 +        // declaration. The collection of those types is all this method implementation does.
 +        if_chain! {
 +            if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
 +            if let Some(&mut StackItem::Check {
 +                impl_id,
 +                ref mut types_to_skip,
 +                ..
 +            }) = self.stack.last_mut();
 +            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id);
 +            then {
 +                // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
 +                // `Self`.
 +                let self_ty = impl_trait_ref.self_ty();
 +
 +                // `trait_method_sig` is the signature of the function, how it is declared in the
 +                // trait, not in the impl of the trait.
 +                let trait_method = cx
 +                    .tcx
 +                    .associated_item(impl_item.def_id)
 +                    .trait_item_def_id
 +                    .expect("impl method matches a trait method");
 +                let trait_method_sig = cx.tcx.fn_sig(trait_method);
 +                let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
 +
 +                // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
 +                // implementation of the trait.
 +                let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
 +                    Some(&**ty)
 +                } else {
 +                    None
 +                };
 +                let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);
 +
 +                // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
 +                //
 +                // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
 +                // trait declaration. This is used to check if `Self` was used in the trait
 +                // declaration.
 +                //
 +                // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
 +                // to `Self`), we want to skip linting that type and all subtypes of it. This
 +                // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
 +                // for u8`, when the trait always uses `Vec<u8>`.
 +                //
 +                // See also https://github.com/rust-lang/rust-clippy/issues/2894.
 +                for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
 +                    if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
 +                        let mut visitor = SkipTyCollector::default();
 +                        visitor.visit_ty(impl_hir_ty);
 +                        types_to_skip.extend(visitor.types_to_skip);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
 +        // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
 +        // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
 +        // However the `node_type()` method can *only* be called in bodies.
 +        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
 +            *in_body = in_body.saturating_add(1);
 +        }
 +    }
 +
 +    fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
 +        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
 +            *in_body = in_body.saturating_sub(1);
 +        }
 +    }
 +
 +    fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
 +        if_chain! {
 +            if !hir_ty.span.from_expansion();
 +            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
 +            if let Some(&StackItem::Check {
 +                impl_id,
 +                in_body,
 +                ref types_to_skip,
 +            }) = self.stack.last();
 +            if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
 +            if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
 +            if !types_to_skip.contains(&hir_ty.hir_id);
 +            let ty = if in_body > 0 {
 +                cx.typeck_results().node_type(hir_ty.hir_id)
 +            } else {
 +                hir_ty_to_ty(cx.tcx, hir_ty)
 +            };
 +            if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
 +            let hir = cx.tcx.hir();
 +            // prevents false positive on `#[derive(serde::Deserialize)]`
 +            if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion();
 +            then {
 +                span_lint(cx, hir_ty.span);
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if !expr.span.from_expansion();
 +            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
 +            if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
 +            if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
 +            then {} else { return; }
 +        }
 +        match expr.kind {
 +            ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
 +                Res::SelfTy { .. } => (),
 +                Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
 +                _ => span_lint(cx, path.span),
 +            },
 +            // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
 +            ExprKind::Call(fun, _) => {
 +                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
 +                    if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
 +                        match ctor_of {
 +                            CtorOf::Variant => lint_path_to_variant(cx, path),
 +                            CtorOf::Struct => span_lint(cx, path.span),
 +                        }
 +                    }
 +                }
 +            },
 +            // unit enum variants (`Enum::A`)
 +            ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
 +        if_chain! {
 +            if !pat.span.from_expansion();
 +            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
 +            if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
 +            if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind;
 +            if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
 +            if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id);
 +            if let [first, ..] = path.segments;
 +            if let Some(hir_id) = first.hir_id;
 +            then {
 +                span_lint(cx, cx.tcx.hir().span(hir_id));
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[derive(Default)]
 +struct SkipTyCollector {
 +    types_to_skip: Vec<HirId>,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for SkipTyCollector {
 +    fn visit_infer(&mut self, inf: &hir::InferArg) {
 +        self.types_to_skip.push(inf.hir_id);
 +
 +        walk_inf(self, inf);
 +    }
 +    fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
 +        self.types_to_skip.push(hir_ty.hir_id);
 +
 +        walk_ty(self, hir_ty);
 +    }
 +}
 +
 +fn span_lint(cx: &LateContext<'_>, span: Span) {
 +    span_lint_and_sugg(
 +        cx,
 +        USE_SELF,
 +        span,
 +        "unnecessary structure name repetition",
 +        "use the applicable keyword",
 +        "Self".to_owned(),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
 +    if let [.., self_seg, _variant] = path.segments {
 +        let span = path
 +            .span
 +            .with_hi(self_seg.args().span_ext().unwrap_or(self_seg.ident.span).hi());
 +        span_lint(cx, span);
 +    }
 +}
index 680b2eb1da723d7696878d7d9f1ed2d27f69ebc7,0000000000000000000000000000000000000000..271c3a3dd181cef4db12b84a6db0f9a3fa42ebf5
mode 100644,000000..100644
--- /dev/null
@@@ -1,371 -1,0 +1,371 @@@
-     /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS.
 +//! 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_METHODS` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedMethod {
 +    Simple(String),
 +    WithReason { path: String, reason: Option<String> },
 +}
 +
 +impl DisallowedMethod {
 +    pub fn path(&self) -> &str {
 +        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
 +
 +        path
 +    }
 +}
 +
 +/// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedType {
 +    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 = "internal")]
 +        pub mod metadata {
 +            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 +
 +            macro_rules! wrap_option {
 +                () => (None);
 +                ($x:literal) => (Some($x));
 +            }
 +
 +            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 +                vec![
 +                    $(
 +                        {
 +                            let deprecation_reason = wrap_option!($($dep)?);
 +
 +                            ClippyConfiguration::new(
 +                                stringify!($name),
 +                                stringify!($ty),
 +                                format!("{:?}", super::defaults::$name()),
 +                                concat!($($doc, '\n',)*),
 +                                deprecation_reason,
 +                            )
 +                        },
 +                    )+
 +                ]
 +            }
 +        }
 +    };
 +}
 +
 +define_Conf! {
 +    /// 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, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED.
 +    ///
 +    /// 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_METHODS.
 +    ///
 +    /// The list of disallowed methods, written as fully qualified paths.
 +    (disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
 +    /// Lint: DISALLOWED_TYPES.
 +    ///
 +    /// The list of disallowed types, written as fully qualified paths.
 +    (disallowed_types: Vec<crate::utils::conf::DisallowedType> = 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: DISALLOWED_SCRIPT_IDENTS.
 +    ///
 +    /// The list of unicode scripts allowed to be used in the scope.
 +    (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
 +    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
 +    ///
 +    /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
 +    (enable_raw_pointer_heuristic_for_send: bool = true),
 +    /// Lint: INDEX_REFUTABLE_SLICE.
 +    ///
 +    /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
 +    /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
 +    /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
 +    (max_suggested_slice_pattern_length: u64 = 3),
 +}
 +
 +/// 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);
 +
 +    let mut found_config: Option<PathBuf> = None;
 +
 +    loop {
 +        for config_file_name in &CONFIG_FILE_NAMES {
 +            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
 +                match fs::metadata(&config_file) {
 +                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
 +                    Err(e) => return Err(e),
 +                    Ok(md) if md.is_dir() => {},
 +                    Ok(_) => {
 +                        // warn if we happen to find two config files #8323
 +                        if let Some(ref found_config_) = found_config {
 +                            eprintln!(
 +                                "Using config file `{}`\nWarning: `{}` will be ignored.",
 +                                found_config_.display(),
 +                                config_file.display(),
 +                            );
 +                        } else {
 +                            found_config = Some(config_file);
 +                        }
 +                    },
 +                }
 +            }
 +        }
 +
 +        if found_config.is_some() {
 +            return Ok(found_config);
 +        }
 +
 +        // If the current directory has no parent, we're done searching.
 +        if !current.pop() {
 +            return Ok(None);
 +        }
 +    }
 +}
 +
 +/// Read the `toml` configuration file.
 +///
 +/// In case of error, the function tries to continue as much as possible.
 +pub fn read(path: &Path) -> TryConf {
 +    let content = match fs::read_to_string(path) {
 +        Err(e) => return TryConf::from_error(e),
 +        Ok(content) => content,
 +    };
 +    toml::from_str(&content).unwrap_or_else(TryConf::from_error)
 +}
index b3b241392fed5d172d7f2649236feeb0318d352d,0000000000000000000000000000000000000000..25d74b8c49939da8a643e60a2da1e4b264440d91
mode 100644,000000..100644
--- /dev/null
@@@ -1,1368 -1,0 +1,1377 @@@
- use rustc_middle::ty::{self, subst::GenericArgKind};
 +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::macros::root_macro_call_first_node;
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::match_type;
 +use clippy_utils::{
 +    def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path,
 +    method_calls, paths, peel_blocks_with_stmt, SpanlessEq,
 +};
 +use if_chain::if_chain;
 +use rustc_ast as ast;
 +use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
 +use rustc_ast::visit::FnKind;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::CRATE_HIR_ID;
 +use rustc_hir::intravisit::Visitor;
 +use rustc_hir::{
 +    BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind,
 +    UnOp,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 +use rustc_middle::hir::nested_filter;
 +use rustc_middle::mir::interpret::ConstValue;
-             Res::Def(DefKind::Const | DefKind::Static, def_id) => {
++use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, FloatTy};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::symbol::Symbol;
 +use rustc_span::{sym, BytePos, Span};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use std::borrow::{Borrow, Cow};
 +
 +#[cfg(feature = "internal")]
 +pub mod metadata_collector;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for various things we like to keep tidy in clippy.
 +    ///
 +    /// ### Why is this bad?
 +    /// We like to pretend we're an example of tidy code.
 +    ///
 +    /// ### Example
 +    /// Wrong ordering of the util::paths constants.
 +    pub CLIPPY_LINTS_INTERNAL,
 +    internal,
 +    "various things that will negatively affect your clippy experience"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Ensures every lint is associated to a `LintPass`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The compiler only knows lints via a `LintPass`. Without
 +    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
 +    /// know the name of the lint.
 +    ///
 +    /// ### Known problems
 +    /// Only checks for lints associated using the
 +    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// declare_lint! { pub LINT_1, ... }
 +    /// declare_lint! { pub LINT_2, ... }
 +    /// declare_lint! { pub FORGOTTEN_LINT, ... }
 +    /// // ...
 +    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
 +    /// // missing FORGOTTEN_LINT
 +    /// ```
 +    pub LINT_WITHOUT_LINT_PASS,
 +    internal,
 +    "declaring a lint without associating it in a LintPass"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
 +    /// variant of the function.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `utils::*` variants also add a link to the Clippy documentation to the
 +    /// warning/error messages.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// cx.span_lint(LINT_NAME, "message");
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::span_lint(cx, LINT_NAME, "message");
 +    /// ```
 +    pub COMPILER_LINT_FUNCTIONS,
 +    internal,
 +    "usage of the lint functions of the compiler instead of the utils::* variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `cx.outer().expn_data()` and suggests to use
 +    /// the `cx.outer_expn_data()`
 +    ///
 +    /// ### Why is this bad?
 +    /// `cx.outer_expn_data()` is faster and more concise.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer().expn_data()
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer_expn_data()
 +    /// ```
 +    pub OUTER_EXPN_EXPN_DATA,
 +    internal,
 +    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Not an actual lint. This lint is only meant for testing our customized internal compiler
 +    /// error message by calling `panic`.
 +    ///
 +    /// ### Why is this bad?
 +    /// ICE in large quantities can damage your teeth
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// 🍦🍦🍦🍦🍦
 +    /// ```
 +    pub PRODUCE_ICE,
 +    internal,
 +    "this message should not appear anywhere as we ICE before and don't emit the lint"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for cases of an auto-generated lint without an updated description,
 +    /// i.e. `default lint description`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Indicates that the lint is not finished.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
 +    /// ```
 +    pub DEFAULT_LINT,
 +    internal,
 +    "found 'default lint description' in a lint declaration"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lints `span_lint_and_then` function calls, where the
 +    /// closure argument has only one statement and that statement is a method
 +    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
 +    /// span), `help` or `note`.
 +    ///
 +    /// These usages of `span_lint_and_then` should be replaced with one of the
 +    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
 +    /// `span_lint_and_note`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using the wrapper `span_lint_and_*` functions, is more
 +    /// convenient, readable and less error prone.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_suggestion(
 +    ///         expr.span,
 +    ///         help_msg,
 +    ///         sugg.to_string(),
 +    ///         Applicability::MachineApplicable,
 +    ///     );
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_help(expr.span, help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.help(help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_note(expr.span, note_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.note(note_msg);
 +    /// });
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     TEST_LINT,
 +    ///     expr.span,
 +    ///     lint_msg,
 +    ///     help_msg,
 +    ///     sugg.to_string(),
 +    ///     Applicability::MachineApplicable,
 +    /// );
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
 +    /// ```
 +    pub COLLAPSIBLE_SPAN_LINT_CALLS,
 +    internal,
 +    "found collapsible `span_lint_and_then` calls"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for calls to `utils::match_type()` on a type diagnostic item
 +    /// and suggests to use `utils::is_type_diagnostic_item()` instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// `utils::is_type_diagnostic_item()` does not require hardcoded paths.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// utils::match_type(cx, ty, &paths::VEC)
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
 +    /// ```
 +    pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    internal,
 +    "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks the paths module for invalid paths.
 +    ///
 +    /// ### Why is this bad?
 +    /// It indicates a bug in the code.
 +    ///
 +    /// ### Example
 +    /// None.
 +    pub INVALID_PATHS,
 +    internal,
 +    "invalid path"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for interning symbols that have already been pre-interned and defined as constants.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster and easier to use the symbol constant.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// let _ = sym!(f32);
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// let _ = sym::f32;
 +    /// ```
 +    pub INTERNING_DEFINED_SYMBOL,
 +    internal,
 +    "interning a symbol that is pre-interned and defined as a constant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary conversion from Symbol to a string.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's faster use symbols directly intead of strings.
 +    ///
 +    /// ### Example
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// symbol.as_str() == "clippy";
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// symbol == sym::clippy;
 +    /// ```
 +    pub UNNECESSARY_SYMBOL_STR,
 +    internal,
 +    "unnecessary conversion between Symbol and string"
 +}
 +
 +declare_clippy_lint! {
 +    /// Finds unidiomatic usage of `if_chain!`
 +    pub IF_CHAIN_STYLE,
 +    internal,
 +    "non-idiomatic `if_chain!` usage"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for invalid `clippy::version` attributes.
 +    ///
 +    /// Valid values are:
 +    /// * "pre 1.29.0"
 +    /// * any valid semantic version
 +    pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +    internal,
 +    "found an invalid `clippy::version` attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for declared clippy lints without the `clippy::version` attribute.
 +    ///
 +    pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +    internal,
 +    "found clippy lint without `clippy::version` attribute"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
 +    ///
 +    pub MISSING_MSRV_ATTR_IMPL,
 +    internal,
 +    "checking if all necessary steps were taken when adding a MSRV to a lint"
 +}
 +
 +declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 +
 +impl EarlyLintPass for ClippyLintsInternal {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
 +        if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
 +            if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
 +                if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
 +                    if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
 +                        let mut last_name: Option<&str> = None;
 +                        for item in items {
 +                            let name = item.ident.as_str();
 +                            if let Some(last_name) = last_name {
 +                                if *last_name > *name {
 +                                    span_lint(
 +                                        cx,
 +                                        CLIPPY_LINTS_INTERNAL,
 +                                        item.span,
 +                                        "this constant should be before the previous constant due to lexical \
 +                                         ordering",
 +                                    );
 +                                }
 +                            }
 +                            last_name = Some(name);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug, Default)]
 +pub struct LintWithoutLintPass {
 +    declared_lints: FxHashMap<Symbol, Span>,
 +    registered_lints: FxHashSet<Symbol>,
 +}
 +
 +impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
 +            return;
 +        }
 +
 +        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
 +            if is_lint_ref_type(cx, ty) {
 +                check_invalid_clippy_version_attribute(cx, item);
 +
 +                let expr = &cx.tcx.hir().body(body_id).value;
 +                if_chain! {
 +                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind;
 +                    if let ExprKind::Struct(_, fields, _) = inner_exp.kind;
 +                    let field = fields
 +                        .iter()
 +                        .find(|f| f.ident.as_str() == "desc")
 +                        .expect("lints must have a description field");
 +                    if let ExprKind::Lit(Spanned {
 +                        node: LitKind::Str(ref sym, _),
 +                        ..
 +                    }) = field.expr.kind;
 +                    if sym.as_str() == "default lint description";
 +
 +                    then {
 +                        span_lint(
 +                            cx,
 +                            DEFAULT_LINT,
 +                            item.span,
 +                            &format!("the lint `{}` has the default lint description", item.ident.name),
 +                        );
 +                    }
 +                }
 +                self.declared_lints.insert(item.ident.name, item.span);
 +            }
 +        } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
 +            if !matches!(
 +                &*cx.tcx.item_name(macro_call.def_id).as_str(),
 +                "impl_lint_pass" | "declare_lint_pass"
 +            ) {
 +                return;
 +            }
 +            if let hir::ItemKind::Impl(hir::Impl {
 +                of_trait: None,
 +                items: impl_item_refs,
 +                ..
 +            }) = item.kind
 +            {
 +                let mut collector = LintCollector {
 +                    output: &mut self.registered_lints,
 +                    cx,
 +                };
 +                let body_id = cx.tcx.hir().body_owned_by(
 +                    impl_item_refs
 +                        .iter()
 +                        .find(|iiref| iiref.ident.as_str() == "get_lints")
 +                        .expect("LintPass needs to implement get_lints")
 +                        .id
 +                        .hir_id(),
 +                );
 +                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
 +            }
 +        }
 +    }
 +
 +    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
 +        if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
 +            return;
 +        }
 +
 +        for (lint_name, &lint_span) in &self.declared_lints {
 +            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
 +            // file points to "<rustc macros>".
 +            // `compiletest-rs` thinks that's an error in a different file and
 +            // just ignores it. This causes the test in compile-fail/lint_pass
 +            // not able to capture the error.
 +            // Therefore, we need to climb the macro expansion tree and find the
 +            // actual span that invoked `declare_tool_lint!`:
 +            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
 +
 +            if !self.registered_lints.contains(lint_name) {
 +                span_lint(
 +                    cx,
 +                    LINT_WITHOUT_LINT_PASS,
 +                    lint_span,
 +                    &format!("the lint `{}` is not added to any `LintPass`", lint_name),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
 +    if let TyKind::Rptr(
 +        _,
 +        MutTy {
 +            ty: inner,
 +            mutbl: Mutability::Not,
 +        },
 +    ) = ty.kind
 +    {
 +        if let TyKind::Path(ref path) = inner.kind {
 +            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
 +                return match_def_path(cx, def_id, &paths::LINT);
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
 +    if let Some(value) = extract_clippy_version_value(cx, item) {
 +        // The `sym!` macro doesn't work as it only expects a single token.
 +        // It's better to keep it this way and have a direct `Symbol::intern` call here.
 +        if value == Symbol::intern("pre 1.29.0") {
 +            return;
 +        }
 +
 +        if RustcVersion::parse(&*value.as_str()).is_err() {
 +            span_lint_and_help(
 +                cx,
 +                INVALID_CLIPPY_VERSION_ATTRIBUTE,
 +                item.span,
 +                "this item has an invalid `clippy::version` attribute",
 +                None,
 +                "please use a valid sematic version, see `doc/adding_lints.md`",
 +            );
 +        }
 +    } else {
 +        span_lint_and_help(
 +            cx,
 +            MISSING_CLIPPY_VERSION_ATTRIBUTE,
 +            item.span,
 +            "this lint is missing the `clippy::version` attribute or version value",
 +            None,
 +            "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
 +        );
 +    }
 +}
 +
 +/// This function extracts the version value of a `clippy::version` attribute if the given value has
 +/// one
 +fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
 +    let attrs = cx.tcx.hir().attrs(item.hir_id());
 +    attrs.iter().find_map(|attr| {
 +        if_chain! {
 +            // Identify attribute
 +            if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
 +            if let [tool_name, attr_name] = &attr_kind.path.segments[..];
 +            if tool_name.ident.name == sym::clippy;
 +            if attr_name.ident.name == sym::version;
 +            if let Some(version) = attr.value_str();
 +            then {
 +                Some(version)
 +            } else {
 +                None
 +            }
 +        }
 +    })
 +}
 +
 +struct LintCollector<'a, 'tcx> {
 +    output: &'a mut FxHashSet<Symbol>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
 +    type NestedFilter = nested_filter::All;
 +
 +    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) -> Self::Map {
 +        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<&str> = method_names.iter().map(Symbol::as_str).collect();
 +        if_chain! {
 +            if let ["expn_data", "outer_expn"] = method_names.as_slice();
 +            let args = arg_lists[1];
 +            if args.len() == 1;
 +            let self_arg = &args[0];
 +            let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +            if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    OUTER_EXPN_EXPN_DATA,
 +                    spans[1].with_hi(expr.span.hi()),
 +                    "usage of `outer_expn().expn_data()`",
 +                    "try",
 +                    "outer_expn_data()".to_string(),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
 +
 +impl EarlyLintPass for ProduceIce {
 +    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
 +        assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
 +    }
 +}
 +
 +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
 +        FnKind::Closure(..) => false,
 +    }
 +}
 +
 +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(func, and_then_args) = expr.kind;
 +            if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
 +            if and_then_args.len() == 5;
 +            if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
 +            let body = cx.tcx.hir().body(*body_id);
 +            let only_expr = peel_blocks_with_stmt(&body.value);
 +            if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind;
 +            then {
 +                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
 +                let mut sle = SpanlessEq::new(cx).deny_side_effects();
 +                match &*ps.ident.as_str() {
 +                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
 +                    },
 +                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
 +                    },
 +                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
 +                    },
 +                    "help" => {
 +                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
 +                    }
 +                    "note" => {
 +                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
 +                    }
 +                    _  => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct AndThenSnippets<'a> {
 +    cx: Cow<'a, str>,
 +    lint: Cow<'a, str>,
 +    span: Cow<'a, str>,
 +    msg: Cow<'a, str>,
 +}
 +
 +fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
 +    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
 +    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
 +    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
 +    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
 +
 +    AndThenSnippets {
 +        cx: cx_snippet,
 +        lint: lint_snippet,
 +        span: span_snippet,
 +        msg: msg_snippet,
 +    }
 +}
 +
 +struct SpanSuggestionSnippets<'a> {
 +    help: Cow<'a, str>,
 +    sugg: Cow<'a, str>,
 +    applicability: Cow<'a, str>,
 +}
 +
 +fn span_suggestion_snippets<'a, 'hir>(
 +    cx: &LateContext<'_>,
 +    span_call_args: &'hir [Expr<'hir>],
 +) -> SpanSuggestionSnippets<'a> {
 +    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
 +    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
 +
 +    SpanSuggestionSnippets {
 +        help: help_snippet,
 +        sugg: sugg_snippet,
 +        applicability: applicability_snippet,
 +    }
 +}
 +
 +fn suggest_suggestion(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
 +) {
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            span_suggestion_snippets.help,
 +            span_suggestion_snippets.sugg,
 +            span_suggestion_snippets.applicability
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_help(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    help: &str,
 +    with_span: bool,
 +) {
 +    let option_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_help({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            &option_span,
 +            help
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_note(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    note: &str,
 +    with_span: bool,
 +) {
 +    let note_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collspible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_note({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            note_span,
 +            note
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
 +
 +impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            // Check if this is a call to utils::match_type()
 +            if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
 +            if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
 +            // Extract the path to the matched type
 +            if let Some(segments) = path_to_matched_type(cx, ty_path);
 +            let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
 +            if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id();
 +            // Check if the matched type is a diagnostic item
 +            if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
 +            then {
 +                // TODO: check paths constants from external crates.
 +                let cx_snippet = snippet(cx, context.span, "_");
 +                let ty_snippet = snippet(cx, ty.span, "_");
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +                    expr.span,
 +                    "usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
 +                    "try",
 +                    format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> {
 +    use rustc_hir::ItemKind;
 +
 +    match &expr.kind {
 +        ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
 +        ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
 +            Res::Local(hir_id) => {
 +                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
 +                if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
 +                    if let Some(init) = local.init {
 +                        return path_to_matched_type(cx, init);
 +                    }
 +                }
 +            },
-     for item_def_id in lang_items.items().iter().flatten() {
++            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<Symbol> = exprs
 +                .iter()
 +                .filter_map(|expr| {
 +                    if let ExprKind::Lit(lit) = &expr.kind {
 +                        if let LitKind::Str(sym, _) = lit.node {
 +                            return Some(sym);
 +                        }
 +                    }
 +
 +                    None
 +                })
 +                .collect();
 +
 +            if segments.len() == exprs.len() {
 +                return Some(segments);
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    None
 +}
 +
 +// This is not a complete resolver for paths. It works on all the paths currently used in the paths
 +// module.  That's all it does and all it needs to do.
 +pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
 +    if def_path_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();
++    // This list isn't complete, but good enough for our current list of paths.
++    let incoherent_impls = [
++        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
++        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
++        SimplifiedTypeGen::SliceSimplifiedType,
++        SimplifiedTypeGen::StrSimplifiedType,
++    ]
++    .iter()
++    .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
++    for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
 +        let lang_item_path = cx.get_def_path(*item_def_id);
 +        if path_syms.starts_with(&lang_item_path) {
 +            if let [item] = &path_syms[lang_item_path.len()..] {
 +                if matches!(
 +                    cx.tcx.def_kind(*item_def_id),
 +                    DefKind::Mod | DefKind::Enum | DefKind::Trait
 +                ) {
 +                    for child in cx.tcx.module_children(*item_def_id) {
 +                        if child.ident.name == *item {
 +                            return true;
 +                        }
 +                    }
 +                } else {
 +                    for child in cx.tcx.associated_item_def_ids(*item_def_id) {
 +                        if cx.tcx.item_name(*child) == *item {
 +                            return true;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +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) = def_path_res(cx, module).opt_def_id() {
 +                for item in cx.tcx.module_children(def_id).iter() {
 +                    if_chain! {
 +                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
 +                        let ty = cx.tcx.type_of(item_def_id);
 +                        if match_type(cx, ty, &paths::SYMBOL);
 +                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
 +                        if let Ok(value) = value.to_u32();
 +                        then {
 +                            self.symbol_map.insert(value, item_def_id);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(func, [arg]) = &expr.kind;
 +            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
 +            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
 +            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
 +            let value = Symbol::intern(&arg).as_u32();
 +            if let Some(&def_id) = self.symbol_map.get(&value);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    INTERNING_DEFINED_SYMBOL,
 +                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
 +                    "interning a defined symbol",
 +                    "try",
 +                    cx.tcx.def_path_str(def_id),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +        if let ExprKind::Binary(op, left, right) = expr.kind {
 +            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
 +                let data = [
 +                    (left, self.symbol_str_expr(left, cx)),
 +                    (right, self.symbol_str_expr(right, cx)),
 +                ];
 +                match data {
 +                    // both operands are a symbol string
 +                    [(_, Some(left)), (_, Some(right))] => {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            UNNECESSARY_SYMBOL_STR,
 +                            expr.span,
 +                            "unnecessary `Symbol` to string conversion",
 +                            "try",
 +                            format!(
 +                                "{} {} {}",
 +                                left.as_symbol_snippet(cx),
 +                                op.node.as_str(),
 +                                right.as_symbol_snippet(cx),
 +                            ),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                    // one of the operands is a symbol string
 +                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
 +                        // creating an owned string for comparison
 +                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                UNNECESSARY_SYMBOL_STR,
 +                                expr.span,
 +                                "unnecessary string allocation",
 +                                "try",
 +                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    },
 +                    // nothing found
 +                    [(_, None), (_, None)] => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl InterningDefinedSymbol {
 +    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
 +        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
 +        static SYMBOL_STR_PATHS: &[&[&str]] = &[
 +            &paths::SYMBOL_AS_STR,
 +            &paths::SYMBOL_TO_IDENT_STRING,
 +            &paths::TO_STRING_METHOD,
 +        ];
 +        let call = if_chain! {
 +            if let ExprKind::AddrOf(_, _, e) = expr.kind;
 +            if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
 +            then { e } else { expr }
 +        };
 +        if_chain! {
 +            // is a method call
 +            if let ExprKind::MethodCall(_, [item], _) = call.kind;
 +            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
 +            let ty = cx.typeck_results().expr_ty(item);
 +            // ...on either an Ident or a Symbol
 +            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
 +                Some(false)
 +            } else if match_type(cx, ty, &paths::IDENT) {
 +                Some(true)
 +            } else {
 +                None
 +            };
 +            // ...which converts it to a string
 +            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
 +            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
 +            then {
 +                let is_to_owned = path.last().unwrap().ends_with("string");
 +                return Some(SymbolStrExpr::Expr {
 +                    item,
 +                    is_ident,
 +                    is_to_owned,
 +                });
 +            }
 +        }
 +        // is a string constant
 +        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
 +            let value = Symbol::intern(&s).as_u32();
 +            // ...which matches a symbol constant
 +            if let Some(&def_id) = self.symbol_map.get(&value) {
 +                return Some(SymbolStrExpr::Const(def_id));
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +enum SymbolStrExpr<'tcx> {
 +    /// a string constant with a corresponding symbol constant
 +    Const(DefId),
 +    /// a "symbol to string" expression like `symbol.as_str()`
 +    Expr {
 +        /// part that evaluates to `Symbol` or `Ident`
 +        item: &'tcx Expr<'tcx>,
 +        is_ident: bool,
 +        /// whether an owned `String` is created like `to_ident_string()`
 +        is_to_owned: bool,
 +    },
 +}
 +
 +impl<'tcx> SymbolStrExpr<'tcx> {
 +    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
 +    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
 +        match *self {
 +            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
 +            Self::Expr { item, is_ident, .. } => {
 +                let mut snip = snippet(cx, item.span.source_callsite(), "..");
 +                if is_ident {
 +                    // get `Ident.name`
 +                    snip.to_mut().push_str(".name");
 +                }
 +                snip
 +            },
 +        }
 +    }
 +}
 +
 +declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
 +    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
 +        let (local, after, if_chain_span) = if_chain! {
 +            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
 +            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
 +            then { (local, after, if_chain_span) } else { return }
 +        };
 +        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be above the `if_chain!`",
 +            );
 +        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
 +            span_lint(
 +                cx,
 +                IF_CHAIN_STYLE,
 +                if_chain_local_span(cx, local, if_chain_span),
 +                "`let` expression should be inside `then { .. }`",
 +            );
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
 +            (cond, then, r#else.is_some())
 +        } else {
 +            return;
 +        };
 +        let then_block = match then.kind {
 +            ExprKind::Block(block, _) => block,
 +            _ => return,
 +        };
 +        let if_chain_span = is_expn_of(expr.span, "if_chain");
 +        if !els {
 +            check_nested_if_chains(cx, expr, then_block, if_chain_span);
 +        }
 +        let if_chain_span = match if_chain_span {
 +            None => return,
 +            Some(span) => span,
 +        };
 +        // check for `if a && b;`
 +        if_chain! {
 +            if let ExprKind::Binary(op, _, _) = cond.kind;
 +            if op.node == BinOpKind::And;
 +            if cx.sess().source_map().is_multiline(cond.span);
 +            then {
 +                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
 +            }
 +        }
 +        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
 +            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
 +        {
 +            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
 +        }
 +    }
 +}
 +
 +fn check_nested_if_chains(
 +    cx: &LateContext<'_>,
 +    if_expr: &Expr<'_>,
 +    then_block: &Block<'_>,
 +    if_chain_span: Option<Span>,
 +) {
 +    #[rustfmt::skip]
 +    let (head, tail) = match *then_block {
 +        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
 +        Block {
 +            stmts: &[
 +                ref head @ ..,
 +                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
 +            ],
 +            ..
 +        } => (head, tail),
 +        _ => return,
 +    };
 +    if_chain! {
 +        if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
 +        let sm = cx.sess().source_map();
 +        if head
 +            .iter()
 +            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
 +        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
 +        then {} else { return }
 +    }
 +    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
 +        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
 +        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
 +        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
 +        _ => return,
 +    };
 +    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
 +        let (span, msg) = match head {
 +            [] => return,
 +            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
 +            [a, .., b] => (
 +                a.span.to(b.span),
 +                "these `let` statements can also be in the `if_chain!`",
 +            ),
 +        };
 +        diag.span_help(span, msg);
 +    });
 +}
 +
 +fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
 +    cx.tcx
 +        .hir()
 +        .parent_iter(hir_id)
 +        .find(|(_, node)| {
 +            #[rustfmt::skip]
 +            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
 +        })
 +        .map_or(false, |(id, _)| {
 +            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
 +        })
 +}
 +
 +/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
 +/// of the `then {..}` portion of an `if_chain!`
 +fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
 +    let span = if let [stmt, ..] = stmts {
 +        stmt.span
 +    } else if let Some(expr) = expr {
 +        expr.span
 +    } else {
 +        // empty `then {}`
 +        return true;
 +    };
 +    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
 +}
 +
 +/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
 +fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
 +    let mut span = local.pat.span;
 +    if let Some(init) = local.init {
 +        span = span.to(init.span);
 +    }
 +    span.adjust(if_chain_span.ctxt().outer_expn());
 +    let sm = cx.sess().source_map();
 +    let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
 +    let span = sm.span_extend_to_next_char(span, ';', false);
 +    Span::new(
 +        span.lo() - BytePos(3),
 +        span.hi() + BytePos(1),
 +        span.ctxt(),
 +        span.parent(),
 +    )
 +}
 +
 +declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
 +
 +impl LateLintPass<'_> for MsrvAttrImpl {
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 +        if_chain! {
 +            if let hir::ItemKind::Impl(hir::Impl {
 +                of_trait: Some(lint_pass_trait_ref),
 +                self_ty,
 +                items,
 +                ..
 +            }) = &item.kind;
 +            if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id();
 +            let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS);
 +            if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS);
 +            let self_ty = hir_ty_to_ty(cx.tcx, self_ty);
 +            if let ty::Adt(self_ty_def, _) = self_ty.kind();
 +            if self_ty_def.is_struct();
 +            if self_ty_def.all_fields().any(|f| {
 +                cx.tcx
 +                    .type_of(f.did)
 +                    .walk()
 +                    .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
 +                    .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
 +            });
 +            if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
 +            then {
 +                let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
 +                let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
 +                let span = cx.sess().source_map().span_through_char(item.span, '{');
 +                span_lint_and_sugg(
 +                    cx,
 +                    MISSING_MSRV_ATTR_IMPL,
 +                    span,
 +                    &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
 +                    &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
 +                    format!("{}\n    extract_msrv_attr!({context});", snippet(cx, span, "..")),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +}
index b3fad6ce7b65137e8a0a6a8e0c0c6fd2210c9c88,0000000000000000000000000000000000000000..ca03b8010dd821c2c68da237efae631c279e1711
mode 100644,000000..100644
--- /dev/null
@@@ -1,925 -1,0 +1,925 @@@
-                 if let hir::def::Res::Def(DefKind::Static, _) = path.res {
 +//! This lint is used to collect metadata about clippy lints. This metadata is exported as a json
 +//! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html)
 +//!
 +//! This module and therefore the entire lint is guarded by a feature flag called `internal`
 +//!
 +//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
 +//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 +//! a simple mistake)
 +
 +use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
 +
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
 +use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
 +use if_chain::if_chain;
 +use rustc_ast as ast;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir::{
 +    self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
 +};
 +use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
 +use rustc_middle::hir::nested_filter;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::Ident;
 +use rustc_span::{sym, Loc, Span, Symbol};
 +use serde::{ser::SerializeStruct, Serialize, Serializer};
 +use std::collections::BinaryHeap;
 +use std::fmt;
 +use std::fs::{self, OpenOptions};
 +use std::io::prelude::*;
 +use std::path::Path;
 +
 +/// This is the output file of the lint collector.
 +const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
 +/// These lints are excluded from the export.
 +const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
 +/// These groups will be ignored by the lint group matcher. This is useful for collections like
 +/// `clippy::all`
 +const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
 +/// Lints within this group will be excluded from the collection. These groups
 +/// have to be defined without the `clippy::` prefix.
 +const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"];
 +/// Collected deprecated lint will be assigned to this group in the JSON output
 +const DEPRECATED_LINT_GROUP_STR: &str = "deprecated";
 +/// This is the lint level for deprecated lints that will be displayed in the lint list
 +const DEPRECATED_LINT_LEVEL: &str = "none";
 +/// This array holds Clippy's lint groups with their corresponding default lint level. The
 +/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`.
 +const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[
 +    ("correctness", "deny"),
 +    ("suspicious", "warn"),
 +    ("restriction", "allow"),
 +    ("style", "warn"),
 +    ("pedantic", "allow"),
 +    ("complexity", "warn"),
 +    ("perf", "warn"),
 +    ("cargo", "allow"),
 +    ("nursery", "allow"),
 +];
 +/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed
 +/// to only keep the actual lint group in the output.
 +const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::";
 +
 +/// This template will be used to format the configuration section in the lint documentation.
 +/// The `configurations` parameter will be replaced with one or multiple formatted
 +/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations
 +macro_rules! CONFIGURATION_SECTION_TEMPLATE {
 +    () => {
 +        r#"
 +### Configuration
 +This lint has the following configuration variables:
 +
 +{configurations}
 +"#
 +    };
 +}
 +/// This template will be used to format an individual `ClippyConfiguration` instance in the
 +/// lint documentation.
 +///
 +/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and
 +/// `default`
 +macro_rules! CONFIGURATION_VALUE_TEMPLATE {
 +    () => {
 +        "* `{name}`: `{ty}`: {doc} (defaults to `{default}`)\n"
 +    };
 +}
 +
 +const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [
 +    &["clippy_utils", "diagnostics", "span_lint"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_help"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_note"],
 +    &["clippy_utils", "diagnostics", "span_lint_hir"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_sugg"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_then"],
 +    &["clippy_utils", "diagnostics", "span_lint_hir_and_then"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"],
 +];
 +const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
 +    ("span_suggestion", false),
 +    ("span_suggestion_short", false),
 +    ("span_suggestion_verbose", false),
 +    ("span_suggestion_hidden", false),
 +    ("tool_only_span_suggestion", false),
 +    ("multipart_suggestion", true),
 +    ("multipart_suggestions", true),
 +    ("tool_only_multipart_suggestion", true),
 +    ("span_suggestions", true),
 +];
 +const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
 +    &["clippy_utils", "diagnostics", "multispan_sugg"],
 +    &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
 +];
 +const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 +
 +/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 +const APPLICABILITY_NAME_INDEX: usize = 2;
 +/// This applicability will be set for unresolved applicability values.
 +const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
 +/// The version that will be displayed if none has been defined
 +const VERION_DEFAULT_STR: &str = "Unknown";
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Collects metadata about clippy lints for the website.
 +    ///
 +    /// This lint will be used to report problems of syntax parsing. You should hopefully never
 +    /// see this but never say never I guess ^^
 +    ///
 +    /// ### Why is this bad?
 +    /// This is not a bad thing but definitely a hacky way to do it. See
 +    /// issue [#4310](https://github.com/rust-lang/rust-clippy/issues/4310) for a discussion
 +    /// about the implementation.
 +    ///
 +    /// ### Known problems
 +    /// Hopefully none. It would be pretty uncool to have a problem here :)
 +    ///
 +    /// ### Example output
 +    /// ```json,ignore
 +    /// {
 +    ///     "id": "internal_metadata_collector",
 +    ///     "id_span": {
 +    ///         "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs",
 +    ///         "line": 1
 +    ///     },
 +    ///     "group": "clippy::internal",
 +    ///     "docs": " ### What it does\nCollects metadata about clippy lints for the website. [...] "
 +    /// }
 +    /// ```
 +    #[clippy::version = "1.56.0"]
 +    pub INTERNAL_METADATA_COLLECTOR,
 +    internal_warn,
 +    "A busy bee collection metadata about lints"
 +}
 +
 +impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Debug, Clone)]
 +pub struct MetadataCollector {
 +    /// All collected lints
 +    ///
 +    /// We use a Heap here to have the lints added in alphabetic order in the export
 +    lints: BinaryHeap<LintMetadata>,
 +    applicability_info: FxHashMap<String, ApplicabilityInfo>,
 +    config: Vec<ClippyConfiguration>,
 +}
 +
 +impl MetadataCollector {
 +    pub fn new() -> Self {
 +        Self {
 +            lints: BinaryHeap::<LintMetadata>::default(),
 +            applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
 +            config: collect_configs(),
 +        }
 +    }
 +
 +    fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
 +        self.config
 +            .iter()
 +            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
 +            .map(ToString::to_string)
 +            .reduce(|acc, x| acc + &x)
 +            .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations))
 +    }
 +}
 +
 +impl Drop for MetadataCollector {
 +    /// You might ask: How hacky is this?
 +    /// My answer:     YES
 +    fn drop(&mut self) {
 +        // The metadata collector gets dropped twice, this makes sure that we only write
 +        // when the list is full
 +        if self.lints.is_empty() {
 +            return;
 +        }
 +
 +        let mut applicability_info = std::mem::take(&mut self.applicability_info);
 +
 +        // Mapping the final data
 +        let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
 +        lints
 +            .iter_mut()
 +            .for_each(|x| x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()));
 +
 +        // Outputting
 +        if Path::new(OUTPUT_FILE).exists() {
 +            fs::remove_file(OUTPUT_FILE).unwrap();
 +        }
 +        let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
 +        writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
 +    }
 +}
 +
 +#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 +struct LintMetadata {
 +    id: String,
 +    id_span: SerializableSpan,
 +    group: String,
 +    level: String,
 +    docs: String,
 +    version: String,
 +    /// This field is only used in the output and will only be
 +    /// mapped shortly before the actual output.
 +    applicability: Option<ApplicabilityInfo>,
 +}
 +
 +impl LintMetadata {
 +    fn new(
 +        id: String,
 +        id_span: SerializableSpan,
 +        group: String,
 +        level: &'static str,
 +        version: String,
 +        docs: String,
 +    ) -> Self {
 +        Self {
 +            id,
 +            id_span,
 +            group,
 +            level: level.to_string(),
 +            version,
 +            docs,
 +            applicability: None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 +struct SerializableSpan {
 +    path: String,
 +    line: usize,
 +}
 +
 +impl std::fmt::Display for SerializableSpan {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{}:{}", self.path.rsplit('/').next().unwrap_or_default(), self.line)
 +    }
 +}
 +
 +impl SerializableSpan {
 +    fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Self {
 +        Self::from_span(cx, item.ident.span)
 +    }
 +
 +    fn from_span(cx: &LateContext<'_>, span: Span) -> Self {
 +        let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo());
 +
 +        Self {
 +            path: format!("{}", loc.file.name.prefer_remapped()),
 +            line: loc.line,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
 +struct ApplicabilityInfo {
 +    /// Indicates if any of the lint emissions uses multiple spans. This is related to
 +    /// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can
 +    /// currently not be applied automatically.
 +    is_multi_part_suggestion: bool,
 +    applicability: Option<usize>,
 +}
 +
 +impl Serialize for ApplicabilityInfo {
 +    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 +    where
 +        S: Serializer,
 +    {
 +        let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?;
 +        s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?;
 +        if let Some(index) = self.applicability {
 +            s.serialize_field(
 +                "applicability",
 +                &paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
 +            )?;
 +        } else {
 +            s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?;
 +        }
 +        s.end()
 +    }
 +}
 +
 +// ==================================================================
 +// Configuration
 +// ==================================================================
 +#[derive(Debug, Clone, Default)]
 +pub struct ClippyConfiguration {
 +    name: String,
 +    config_type: &'static str,
 +    default: String,
 +    lints: Vec<String>,
 +    doc: String,
 +    #[allow(dead_code)]
 +    deprecation_reason: Option<&'static str>,
 +}
 +
 +impl ClippyConfiguration {
 +    pub fn new(
 +        name: &'static str,
 +        config_type: &'static str,
 +        default: String,
 +        doc_comment: &'static str,
 +        deprecation_reason: Option<&'static str>,
 +    ) -> Self {
 +        let (lints, doc) = parse_config_field_doc(doc_comment)
 +            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
 +
 +        Self {
 +            name: to_kebab(name),
 +            lints,
 +            doc,
 +            config_type,
 +            default,
 +            deprecation_reason,
 +        }
 +    }
 +}
 +
 +fn collect_configs() -> Vec<ClippyConfiguration> {
 +    crate::utils::conf::metadata::get_configuration_metadata()
 +}
 +
 +/// This parses the field documentation of the config struct.
 +///
 +/// ```rust, ignore
 +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
 +/// ```
 +///
 +/// Would yield:
 +/// ```rust, ignore
 +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
 +/// ```
 +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
 +    const DOC_START: &str = " Lint: ";
 +    if_chain! {
 +        if doc_comment.starts_with(DOC_START);
 +        if let Some(split_pos) = doc_comment.find('.');
 +        then {
 +            let mut doc_comment = doc_comment.to_string();
 +            let mut documentation = doc_comment.split_off(split_pos);
 +
 +            // Extract lints
 +            doc_comment.make_ascii_lowercase();
 +            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
 +
 +            // Format documentation correctly
 +            // split off leading `.` from lint name list and indent for correct formatting
 +            documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
 +
 +            Some((lints, documentation))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
 +fn to_kebab(config_name: &str) -> String {
 +    config_name.replace('_', "-")
 +}
 +
 +impl fmt::Display for ClippyConfiguration {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
 +        write!(
 +            f,
 +            CONFIGURATION_VALUE_TEMPLATE!(),
 +            name = self.name,
 +            ty = self.config_type,
 +            doc = self.doc,
 +            default = self.default
 +        )
 +    }
 +}
 +
 +// ==================================================================
 +// Lint pass
 +// ==================================================================
 +impl<'hir> LateLintPass<'hir> for MetadataCollector {
 +    /// Collecting lint declarations like:
 +    /// ```rust, ignore
 +    /// declare_clippy_lint! {
 +    ///     /// ### What it does
 +    ///     /// Something IDK.
 +    ///     pub SOME_LINT,
 +    ///     internal,
 +    ///     "Who am I?"
 +    /// }
 +    /// ```
 +    fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
 +        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
 +            // Normal lint
 +            if_chain! {
 +                // item validation
 +                if is_lint_ref_type(cx, ty);
 +                // blacklist check
 +                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
 +                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
 +                // metadata extraction
 +                if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
 +                if let Some(mut docs) = extract_attr_docs_or_lint(cx, item);
 +                then {
 +                    if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
 +                        docs.push_str(&configuration_section);
 +                    }
 +                    let version = get_lint_version(cx, item);
 +
 +                    self.lints.push(LintMetadata::new(
 +                        lint_name,
 +                        SerializableSpan::from_item(cx, item),
 +                        group,
 +                        level,
 +                        version,
 +                        docs,
 +                    ));
 +                }
 +            }
 +
 +            if_chain! {
 +                if is_deprecated_lint(cx, ty);
 +                // blacklist check
 +                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
 +                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
 +                // Metadata the little we can get from a deprecated lint
 +                if let Some(docs) = extract_attr_docs_or_lint(cx, item);
 +                then {
 +                    let version = get_lint_version(cx, item);
 +
 +                    self.lints.push(LintMetadata::new(
 +                        lint_name,
 +                        SerializableSpan::from_item(cx, item),
 +                        DEPRECATED_LINT_GROUP_STR.to_string(),
 +                        DEPRECATED_LINT_LEVEL,
 +                        version,
 +                        docs,
 +                    ));
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Collecting constant applicability from the actual lint emissions
 +    ///
 +    /// Example:
 +    /// ```rust, ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     SOME_LINT,
 +    ///     item.span,
 +    ///     "Le lint message",
 +    ///     "Here comes help:",
 +    ///     "#![allow(clippy::all)]",
 +    ///     Applicability::MachineApplicable, // <-- Extracts this constant value
 +    /// );
 +    /// ```
 +    fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) {
 +        if let Some(args) = match_lint_emission(cx, expr) {
 +            let emission_info = extract_emission_info(cx, args);
 +            if emission_info.is_empty() {
 +                // See:
 +                // - src/misc.rs:734:9
 +                // - src/methods/mod.rs:3545:13
 +                // - src/methods/mod.rs:3496:13
 +                // We are basically unable to resolve the lint name itself.
 +                return;
 +            }
 +
 +            for (lint_name, applicability, is_multi_part) in emission_info {
 +                let app_info = self.applicability_info.entry(lint_name).or_default();
 +                app_info.applicability = applicability;
 +                app_info.is_multi_part_suggestion = is_multi_part;
 +            }
 +        }
 +    }
 +}
 +
 +// ==================================================================
 +// Lint definition extraction
 +// ==================================================================
 +fn sym_to_string(sym: Symbol) -> String {
 +    sym.as_str().to_string()
 +}
 +
 +fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
 +    extract_attr_docs(cx, item).or_else(|| {
 +        lint_collection_error_item(cx, item, "could not collect the lint documentation");
 +        None
 +    })
 +}
 +
 +/// This function collects all documentation that has been added to an item using
 +/// `#[doc = r""]` attributes. Several attributes are aggravated using line breaks
 +///
 +/// ```ignore
 +/// #[doc = r"Hello world!"]
 +/// #[doc = r"=^.^="]
 +/// struct SomeItem {}
 +/// ```
 +///
 +/// Would result in `Hello world!\n=^.^=\n`
 +///
 +/// ---
 +///
 +/// This function may modify the doc comment to ensure that the string can be displayed using a
 +/// markdown viewer in Clippy's lint list. The following modifications could be applied:
 +/// * Removal of leading space after a new line. (Important to display tables)
 +/// * Ensures that code blocks only contain language information
 +fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
 +    let attrs = cx.tcx.hir().attrs(item.hir_id());
 +    let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
 +    let mut docs = String::from(&*lines.next()?.as_str());
 +    let mut in_code_block = false;
 +    let mut is_code_block_rust = false;
 +    for line in lines {
 +        let line = line.as_str();
 +        let line = &*line;
 +
 +        // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
 +        if is_code_block_rust && line.trim_start().starts_with("# ") {
 +            continue;
 +        }
 +
 +        // The line should be represented in the lint list, even if it's just an empty line
 +        docs.push('\n');
 +        if let Some(info) = line.trim_start().strip_prefix("```") {
 +            in_code_block = !in_code_block;
 +            is_code_block_rust = false;
 +            if in_code_block {
 +                let lang = info
 +                    .trim()
 +                    .split(',')
 +                    // remove rustdoc directives
 +                    .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic"))
 +                    // if no language is present, fill in "rust"
 +                    .unwrap_or("rust");
 +                docs.push_str("```");
 +                docs.push_str(lang);
 +
 +                is_code_block_rust = lang == "rust";
 +                continue;
 +            }
 +        }
 +        // This removes the leading space that the macro translation introduces
 +        if let Some(stripped_doc) = line.strip_prefix(' ') {
 +            docs.push_str(stripped_doc);
 +        } else if !line.is_empty() {
 +            docs.push_str(line);
 +        }
 +    }
 +    Some(docs)
 +}
 +
 +fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String {
 +    extract_clippy_version_value(cx, item).map_or_else(
 +        || VERION_DEFAULT_STR.to_string(),
 +        |version| version.as_str().to_string(),
 +    )
 +}
 +
 +fn get_lint_group_and_level_or_lint(
 +    cx: &LateContext<'_>,
 +    lint_name: &str,
 +    item: &Item<'_>,
 +) -> Option<(String, &'static str)> {
 +    let result = cx.lint_store.check_lint_name(
 +        lint_name,
 +        Some(sym::clippy),
 +        &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
 +    );
 +    if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
 +        if let Some(group) = get_lint_group(cx, lint_lst[0]) {
 +            if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
 +                return None;
 +            }
 +
 +            if let Some(level) = get_lint_level_from_group(&group) {
 +                Some((group, level))
 +            } else {
 +                lint_collection_error_item(
 +                    cx,
 +                    item,
 +                    &format!("Unable to determine lint level for found group `{}`", group),
 +                );
 +                None
 +            }
 +        } else {
 +            lint_collection_error_item(cx, item, "Unable to determine lint group");
 +            None
 +        }
 +    } else {
 +        lint_collection_error_item(cx, item, "Unable to find lint in lint_store");
 +        None
 +    }
 +}
 +
 +fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
 +    for (group_name, lints, _) in cx.lint_store.get_lint_groups() {
 +        if IGNORED_LINT_GROUPS.contains(&group_name) {
 +            continue;
 +        }
 +
 +        if lints.iter().any(|group_lint| *group_lint == lint_id) {
 +            let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name);
 +            return Some((*group).to_string());
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
 +    DEFAULT_LINT_LEVELS
 +        .iter()
 +        .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level))
 +}
 +
 +fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if let hir::TyKind::Path(ref path) = ty.kind {
 +        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
 +            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
 +        }
 +    }
 +
 +    false
 +}
 +
 +// ==================================================================
 +// Lint emission
 +// ==================================================================
 +fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) {
 +    span_lint(
 +        cx,
 +        INTERNAL_METADATA_COLLECTOR,
 +        item.ident.span,
 +        &format!("metadata collection error for `{}`: {}", item.ident.name, message),
 +    );
 +}
 +
 +// ==================================================================
 +// Applicability
 +// ==================================================================
 +/// This function checks if a given expression is equal to a simple lint emission function call.
 +/// It will return the function arguments if the emission matched any function.
 +fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) -> Option<&'hir [hir::Expr<'hir>]> {
 +    LINT_EMISSION_FUNCTIONS
 +        .iter()
 +        .find_map(|emission_fn| match_function_call(cx, expr, emission_fn))
 +}
 +
 +fn take_higher_applicability(a: Option<usize>, b: Option<usize>) -> Option<usize> {
 +    a.map_or(b, |a| a.max(b.unwrap_or_default()).into())
 +}
 +
 +fn extract_emission_info<'hir>(
 +    cx: &LateContext<'hir>,
 +    args: &'hir [hir::Expr<'hir>],
 +) -> Vec<(String, Option<usize>, bool)> {
 +    let mut lints = Vec::new();
 +    let mut applicability = None;
 +    let mut multi_part = false;
 +
 +    for arg in args {
 +        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
 +
 +        if match_type(cx, arg_ty, &paths::LINT) {
 +            // If we found the lint arg, extract the lint name
 +            let mut resolved_lints = resolve_lints(cx, arg);
 +            lints.append(&mut resolved_lints);
 +        } else if match_type(cx, arg_ty, &paths::APPLICABILITY) {
 +            applicability = resolve_applicability(cx, arg);
 +        } else if arg_ty.is_closure() {
 +            multi_part |= check_is_multi_part(cx, arg);
 +            applicability = applicability.or_else(|| resolve_applicability(cx, arg));
 +        }
 +    }
 +
 +    lints
 +        .into_iter()
 +        .map(|lint_name| (lint_name, applicability, multi_part))
 +        .collect()
 +}
 +
 +/// Resolves the possible lints that this expression could reference
 +fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
 +    let mut resolver = LintResolver::new(cx);
 +    resolver.visit_expr(expr);
 +    resolver.lints
 +}
 +
 +/// This function tries to resolve the linked applicability to the given expression.
 +fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
 +    let mut resolver = ApplicabilityResolver::new(cx);
 +    resolver.visit_expr(expr);
 +    resolver.complete()
 +}
 +
 +fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
 +    if let ExprKind::Closure(_, _, body_id, _, _) = closure_expr.kind {
 +        let mut scanner = IsMultiSpanScanner::new(cx);
 +        intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body_id));
 +        return scanner.is_multi_part();
 +    } else if let Some(local) = get_parent_local(cx, closure_expr) {
 +        if let Some(local_init) = local.init {
 +            return check_is_multi_part(cx, local_init);
 +        }
 +    }
 +
 +    false
 +}
 +
 +struct LintResolver<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    lints: Vec<String>,
 +}
 +
 +impl<'a, 'hir> LintResolver<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            lints: Vec::<String>::default(),
 +        }
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
 +    type NestedFilter = nested_filter::All;
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        if_chain! {
 +            if let ExprKind::Path(qpath) = &expr.kind;
 +            if let QPath::Resolved(_, path) = qpath;
 +
 +            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 +            if match_type(self.cx, expr_ty, &paths::LINT);
 +            then {
++                if let hir::def::Res::Def(DefKind::Static(..), _) = path.res {
 +                    let lint_name = last_path_segment(qpath).ident.name;
 +                    self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
 +                } else if let Some(local) = get_parent_local(self.cx, expr) {
 +                    if let Some(local_init) = local.init {
 +                        intravisit::walk_expr(self, local_init);
 +                    }
 +                }
 +            }
 +        }
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
 +
 +/// This visitor finds the highest applicability value in the visited expressions
 +struct ApplicabilityResolver<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    /// This is the index of hightest `Applicability` for `paths::APPLICABILITY_VALUES`
 +    applicability_index: Option<usize>,
 +}
 +
 +impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            applicability_index: None,
 +        }
 +    }
 +
 +    fn add_new_index(&mut self, new_index: usize) {
 +        self.applicability_index = take_higher_applicability(self.applicability_index, Some(new_index));
 +    }
 +
 +    fn complete(self) -> Option<usize> {
 +        self.applicability_index
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
 +    type NestedFilter = nested_filter::All;
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +
 +    fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
 +        for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
 +            if match_path(path, enum_value) {
 +                self.add_new_index(index);
 +                return;
 +            }
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 +
 +        if_chain! {
 +            if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
 +            if let Some(local) = get_parent_local(self.cx, expr);
 +            if let Some(local_init) = local.init;
 +            then {
 +                intravisit::walk_expr(self, local_init);
 +            }
 +        };
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
 +
 +/// This returns the parent local node if the expression is a reference one
 +fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
 +    if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
 +        if let hir::def::Res::Local(local_hir) = path.res {
 +            return get_parent_local_hir_id(cx, local_hir);
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
 +    let map = cx.tcx.hir();
 +
 +    match map.find(map.get_parent_node(hir_id)) {
 +        Some(hir::Node::Local(local)) => Some(local),
 +        Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
 +        _ => None,
 +    }
 +}
 +
 +/// This visitor finds the highest applicability value in the visited expressions
 +struct IsMultiSpanScanner<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    suggestion_count: usize,
 +}
 +
 +impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            suggestion_count: 0,
 +        }
 +    }
 +
 +    /// Add a new single expression suggestion to the counter
 +    fn add_single_span_suggestion(&mut self) {
 +        self.suggestion_count += 1;
 +    }
 +
 +    /// Signals that a suggestion with possible multiple spans was found
 +    fn add_multi_part_suggestion(&mut self) {
 +        self.suggestion_count += 2;
 +    }
 +
 +    /// Checks if the suggestions include multiple spanns
 +    fn is_multi_part(&self) -> bool {
 +        self.suggestion_count > 1
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
 +    type NestedFilter = nested_filter::All;
 +
 +    fn nested_visit_map(&mut self) -> Self::Map {
 +        self.cx.tcx.hir()
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        // Early return if the lint is already multi span
 +        if self.is_multi_part() {
 +            return;
 +        }
 +
 +        match &expr.kind {
 +            ExprKind::Call(fn_expr, _args) => {
 +                let found_function = SUGGESTION_FUNCTIONS
 +                    .iter()
 +                    .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
 +                if found_function {
 +                    // These functions are all multi part suggestions
 +                    self.add_single_span_suggestion();
 +                }
 +            },
 +            ExprKind::MethodCall(path, arg, _arg_span) => {
 +                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0]));
 +                if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) {
 +                    let called_method = path.ident.name.as_str().to_string();
 +                    for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS {
 +                        if *method_name == called_method {
 +                            if *is_multi_part {
 +                                self.add_multi_part_suggestion();
 +                            } else {
 +                                self.add_single_span_suggestion();
 +                            }
 +                            break;
 +                        }
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
index d3ed8da4499f88ee3aec2578e4983ffb1516dc51,0000000000000000000000000000000000000000..0b1fd95c3453d1ba4f6e5e653d47488ac3f1b1ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,18 @@@
- version = "0.1.61"
 +[package]
 +name = "clippy_utils"
++version = "0.1.62"
 +edition = "2021"
 +publish = false
 +
 +[dependencies]
 +arrayvec = { version = "0.7", default-features = false }
 +if_chain = "1.0"
 +rustc-semver = "1.1"
 +
 +[features]
 +deny-warnings = []
 +internal = []
 +
 +[package.metadata.rust-analyzer]
 +# This crate uses #[feature(rustc_private)]
 +rustc_private = true
index 62e144398012d4b5780c83bbe51f44a2efc5928e,0000000000000000000000000000000000000000..a275bac4ce63dc5436ea18d4677f8c219c50488c
mode 100644,000000..100644
--- /dev/null
@@@ -1,2185 -1,0 +1,2188 @@@
-     def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr,
-     ExprKind, FnDecl, ForeignItem, 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,
 +#![feature(box_patterns)]
 +#![feature(control_flow_enum)]
 +#![feature(let_else)]
 +#![feature(let_chains)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
 +// warn on the same lints as `clippy_lints`
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +pub mod sym_helper;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
 +pub mod comparisons;
 +pub mod consts;
 +pub mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +pub mod macros;
 +pub mod msrvs;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod qualify_min_const_fn;
 +pub mod source;
 +pub mod str_utils;
 +pub mod sugg;
 +pub mod ty;
 +pub mod usage;
 +pub mod visitors;
 +
 +pub use self::attrs::*;
 +pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +use std::lazy::SyncOnceCell;
 +use std::sync::{Mutex, MutexGuard};
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_data_structures::unhash::UnhashMap;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
 +use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 +use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 +use rustc_hir::itemlikevisit::ItemLikeVisitor;
 +use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 +use rustc_hir::{
- use rustc_middle::ty::{IntTy, UintTy, FloatTy};
- use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
++    def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
++    ForeignItem, 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::place::PlaceBase;
 +use rustc_middle::ty as rustc_ty;
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::binding::BindingMode;
-         .flat_map(|id| item_child_by_name(tcx, id, first));
++use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
++    ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
++    PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
++};
 +use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
++use rustc_middle::ty::{FloatTy, IntTy, UintTy};
 +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};
 +use crate::visitors::expr_visitor_no_bodies;
 +
 +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
 +    if let Ok(version) = RustcVersion::parse(msrv) {
 +        return Some(version);
 +    } else if let Some(sess) = sess {
 +        if let Some(span) = span {
 +            sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
 +        }
 +    }
 +    None
 +}
 +
 +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
 +    msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
 +}
 +
 +#[macro_export]
 +macro_rules! extract_msrv_attr {
 +    ($context:ident) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
 +            let sess = rustc_lint::LintContext::sess(cx);
 +            match $crate::get_unique_inner_attr(sess, attrs, "msrv") {
 +                Some(msrv_attr) => {
 +                    if let Some(msrv) = msrv_attr.value_str() {
 +                        self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
 +                    } else {
 +                        sess.span_err(msrv_attr.span, "bad clippy attribute");
 +                    }
 +                },
 +                _ => (),
 +            }
 +        }
 +    };
 +}
 +
 +/// If the given expression is a local binding, find the initializer expression.
 +/// If that initializer expression is another local binding, find its initializer again.
 +/// This process repeats as long as possible (but usually no more than once). Initializer
 +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
 +/// instead.
 +///
 +/// Examples:
 +/// ```
 +/// let abc = 1;
 +/// //        ^ output
 +/// let def = abc;
 +/// dbg!(def);
 +/// //   ^^^ input
 +///
 +/// // or...
 +/// let abc = 1;
 +/// let def = abc + 2;
 +/// //        ^^^^^^^ output
 +/// dbg!(def);
 +/// //   ^^^ input
 +/// ```
 +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
 +    while let Some(init) = path_to_local(expr)
 +        .and_then(|id| find_binding_init(cx, id))
 +        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
 +    {
 +        expr = init;
 +    }
 +    expr
 +}
 +
 +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
 +/// By only considering immutable bindings, we guarantee that the returned expression represents the
 +/// value of the binding wherever it is referenced.
 +///
 +/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
 +/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
 +/// canonical binding `HirId`.
 +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
 +    let hir = cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::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_by_def_id(parent_id) {
 +        Node::Item(&Item {
 +            kind: ItemKind::Const(..) | ItemKind::Static(..),
 +            ..
 +        })
 +        | Node::TraitItem(&TraitItem {
 +            kind: TraitItemKind::Const(..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Const(..),
 +            ..
 +        })
 +        | Node::AnonConst(_) => true,
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(ref sig, ..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(ref sig, _),
 +            ..
 +        }) => sig.header.constness == Constness::Const,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if a `QPath` resolves to a constructor of a `LangItem`.
 +/// For example, use this to check whether a function call or a pattern is `Some(..)`.
 +pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool {
 +    if let QPath::Resolved(_, path) = qpath {
 +        if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
 +            if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
 +                return cx.tcx.parent(ctor_id) == Some(item_id);
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
 +    matches!(
 +        expr.kind,
 +        ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr: None,
 +                ..
 +            },
 +            _
 +        ) | ExprKind::Tup([])
 +    )
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild(pat: &Pat<'_>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +/// This is a deprecated function, consider using [`is_trait_method`].
 +pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
 +    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +    let trt_id = cx.tcx.trait_of_item(def_id);
 +    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 +}
 +
 +/// Checks if a method is defined in an impl of a diagnostic item
 +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +        if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +            return cx.tcx.is_diagnostic_item(diag_item, adt.did());
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if a method is in a diagnostic item trait
 +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
 +        return cx.tcx.is_diagnostic_item(diag_item, trait_did);
 +    }
 +    false
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    cx.typeck_results()
 +        .type_dependent_def_id(expr.hir_id)
 +        .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 +}
 +
 +/// Checks if the given expression is a path referring an item on the trait
 +/// that is marked with the given diagnostic item.
 +///
 +/// For checking method call expressions instead of path expressions, use
 +/// [`is_trait_method`].
 +///
 +/// For example, this can be used to find if an expression like `u64::default`
 +/// refers to an item of the trait `Default`, which is associated with the
 +/// `diag_item` of `sym::Default`.
 +pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    if let hir::ExprKind::Path(ref qpath) = expr.kind {
 +        cx.qpath_res(qpath, expr.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
 +    last_path_segment(qpath)
 +        .args
 +        .map_or(&[][..], |a| a.args)
 +        .iter()
 +        .filter_map(|a| match a {
 +            hir::GenericArg::Type(ty) => Some(ty),
 +            _ => None,
 +        })
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `QPath` against a slice of segment string literals.
 +///
 +/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
 +/// `rustc_hir::QPath`.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_qpath(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 +    match *path {
 +        QPath::Resolved(_, path) => match_path(path, segments),
 +        QPath::TypeRelative(ty, segment) => match ty.kind {
 +            TyKind::Path(ref inner_path) => {
 +                if let [prefix @ .., end] = segments {
 +                    if match_qpath(inner_path, prefix) {
 +                        return segment.ident.name.as_str() == *end;
 +                    }
 +                }
 +                false
 +            },
 +            _ => false,
 +        },
 +        QPath::LangItem(..) => false,
 +    }
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 +///
 +/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
 +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
 +    path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If 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 {
 +    path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `Path` against a slice of segment string literals.
 +///
 +/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
 +/// `rustc_hir::Path`.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// if match_path(&trait_ref.path, &paths::HASH) {
 +///     // This is the `std::hash::Hash` trait.
 +/// }
 +///
 +/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
 +///     // This is a `rustc_middle::lint::Lint`.
 +/// }
 +/// ```
 +pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// If the expression is a path to a local, returns the canonical `HirId` of the local.
 +pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
 +    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
 +        if let Res::Local(id) = path.res {
 +            return Some(id);
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns true if the expression is a path to a local with the specified `HirId`.
 +/// Use this function to see if an expression matches a function argument or a match binding.
 +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
 +    path_to_local(expr) == Some(id)
 +}
 +
 +pub trait MaybePath<'hir> {
 +    fn hir_id(&self) -> HirId;
 +    fn qpath_opt(&self) -> Option<&QPath<'hir>>;
 +}
 +
 +macro_rules! maybe_path {
 +    ($ty:ident, $kind:ident) => {
 +        impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
 +            fn hir_id(&self) -> HirId {
 +                self.hir_id
 +            }
 +            fn qpath_opt(&self) -> Option<&QPath<'hir>> {
 +                match &self.kind {
 +                    hir::$kind::Path(qpath) => Some(qpath),
 +                    _ => None,
 +                }
 +            }
 +        }
 +    };
 +}
 +maybe_path!(Expr, ExprKind);
 +maybe_path!(Pat, PatKind);
 +maybe_path!(Ty, TyKind);
 +
 +/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
 +pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
 +    match maybe_path.qpath_opt() {
 +        None => Res::Err,
 +        Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
 +    }
 +}
 +
 +/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
 +pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
 +    path_res(cx, maybe_path).opt_def_id()
 +}
 +
 +/// Resolves a def path like `std::vec::Vec`.
 +/// This function is expensive and should be used sparingly.
 +pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
 +    fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> {
 +        match tcx.def_kind(def_id) {
 +            DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
 +                .module_children(def_id)
 +                .iter()
 +                .find(|item| item.ident.name.as_str() == name)
 +                .map(|child| child.res.expect_non_local()),
 +            DefKind::Impl => tcx
 +                .associated_item_def_ids(def_id)
 +                .iter()
 +                .copied()
 +                .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
 +                .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
 +            _ => None,
 +        }
 +    }
 +    fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
 +        let single = |ty| tcx.incoherent_impls(ty).iter().copied();
 +        let empty = || [].iter().copied();
 +        match name {
 +            "bool" => single(BoolSimplifiedType),
 +            "char" => single(CharSimplifiedType),
 +            "str" => single(StrSimplifiedType),
 +            "array" => single(ArraySimplifiedType),
 +            "slice" => single(SliceSimplifiedType),
 +            // FIXME: rustdoc documents these two using just `pointer`.
 +            //
 +            // Maybe this is something we should do here too.
 +            "const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
 +            "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
 +            "isize" => single(IntSimplifiedType(IntTy::Isize)),
 +            "i8" => single(IntSimplifiedType(IntTy::I8)),
 +            "i16" => single(IntSimplifiedType(IntTy::I16)),
 +            "i32" => single(IntSimplifiedType(IntTy::I32)),
 +            "i64" => single(IntSimplifiedType(IntTy::I64)),
 +            "i128" => single(IntSimplifiedType(IntTy::I128)),
 +            "usize" => single(UintSimplifiedType(UintTy::Usize)),
 +            "u8" => single(UintSimplifiedType(UintTy::U8)),
 +            "u16" => single(UintSimplifiedType(UintTy::U16)),
 +            "u32" => single(UintSimplifiedType(UintTy::U32)),
 +            "u64" => single(UintSimplifiedType(UintTy::U64)),
 +            "u128" => single(UintSimplifiedType(UintTy::U128)),
 +            "f32" => single(FloatSimplifiedType(FloatTy::F32)),
 +            "f64" => single(FloatSimplifiedType(FloatTy::F64)),
 +            _ => empty(),
 +        }
 +    }
 +    fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
 +        tcx.crates(())
 +            .iter()
 +            .copied()
 +            .find(|&num| tcx.crate_name(num).as_str() == name)
 +            .map(CrateNum::as_def_id)
 +    }
 +
 +    let (base, first, path) = match *path {
 +        [base, first, ref path @ ..] => (base, first, path),
 +        [primitive] => {
 +            return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
 +        },
 +        _ => return Res::Err,
 +    };
 +    let tcx = cx.tcx;
 +    let starts = find_primitive(tcx, base)
 +        .chain(find_crate(tcx, base))
++        .filter_map(|id| item_child_by_name(tcx, id, first));
 +
 +    for first in starts {
 +        let last = path
 +            .iter()
 +            .copied()
 +            // for each segment, find the child item
 +            .try_fold(first, |res, segment| {
 +                let def_id = res.def_id();
 +                if let Some(item) = item_child_by_name(tcx, def_id, segment) {
 +                    Some(item)
 +                } else if matches!(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
 +                }
 +            });
 +
 +        if let Some(last) = last {
 +            return last;
 +        }
 +    }
 +
 +    Res::Err
 +}
 +
 +/// Convenience function to get the `DefId` of a trait by path.
 +/// It could be a trait or trait alias.
 +pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 +    match def_path_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>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != CRATE_DEF_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(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)
 +}
 +
 +/// Gets the mutability of the custom deref adjustment, if any.
 +pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {
 +    cx.typeck_results()
 +        .expr_adjustments(e)
 +        .iter()
 +        .find_map(|a| match a.kind {
 +            Adjust::Deref(Some(d)) => Some(Some(d.mutbl)),
 +            Adjust::Deref(None) => None,
 +            _ => Some(None),
 +        })
 +        .and_then(|x| x)
 +}
 +
 +/// Checks if two expressions can be mutably borrowed simultaneously
 +/// and they aren't dependent on borrowing same thing twice
 +pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
 +    let (s1, r1) = projection_stack(e1);
 +    let (s2, r2) = projection_stack(e2);
 +    if !eq_expr_value(cx, r1, r2) {
 +        return true;
 +    }
 +    if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {
 +        return false;
 +    }
 +
 +    for (x1, x2) in s1.iter().zip(s2.iter()) {
 +        if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {
 +            return false;
 +        }
 +
 +        match (&x1.kind, &x2.kind) {
 +            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
 +                if i1 != i2 {
 +                    return true;
 +                }
 +            },
 +            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
 +                if !eq_expr_value(cx, i1, i2) {
 +                    return false;
 +                }
 +            },
 +            _ => return false,
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
 +/// constructor from the std library
 +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
 +    let std_types_symbols = &[
 +        sym::String,
 +        sym::Vec,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::HashMap,
 +        sym::BTreeMap,
 +        sym::HashSet,
 +        sym::BTreeSet,
 +        sym::BinaryHeap,
 +    ];
 +
 +    if let QPath::TypeRelative(_, method) = path {
 +        if method.ident.name == sym::new {
 +            if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +                if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +                    return std_types_symbols
 +                        .iter()
 +                        .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did()));
 +                }
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// Return true if the expr is equal to `Default::default` when evaluated.
 +pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
 +    if_chain! {
 +        if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
 +        if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
 +        if is_diag_trait_item(cx, repl_def_id, sym::Default)
 +            || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
 +        then { true } else { false }
 +    }
 +}
 +
 +/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
 +/// It doesn't cover all cases, for example indirect function calls (some of std
 +/// functions are supported) but it is the best we have.
 +pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    match &e.kind {
 +        ExprKind::Lit(lit) => match lit.node {
 +            LitKind::Bool(false) | LitKind::Int(0, _) => true,
 +            LitKind::Str(s, _) => s.is_empty(),
 +            _ => false,
 +        },
 +        ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
 +        ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
 +            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
 +            if let LitKind::Int(v, _) = const_lit.node;
 +            if v <= 32 && is_default_equivalent(cx, x);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
 +        ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func),
 +        ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
 +        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the top level expression can be moved into a closure as is.
 +/// Currently checks for:
 +/// * Break/Continue outside the given loop HIR ids.
 +/// * Yield/Return statements.
 +/// * Inline assembly.
 +/// * Usages of a field of a local where the type of the local can be partially moved.
 +///
 +/// For example, given the following function:
 +///
 +/// ```
 +/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
 +///     for item in iter {
 +///         let s = item.1;
 +///         if item.0 > 10 {
 +///             continue;
 +///         } else {
 +///             s.clear();
 +///         }
 +///     }
 +/// }
 +/// ```
 +///
 +/// When called on the expression `item.0` this will return false unless the local `item` is in the
 +/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
 +/// isn't always safe to move into a closure when only a single field is needed.
 +///
 +/// When called on the `continue` expression this will return false unless the outer loop expression
 +/// is in the `loop_ids` set.
 +///
 +/// Note that this check is not recursive, so passing the `if` expression will always return true
 +/// even though sub-expressions might return false.
 +pub fn can_move_expr_to_closure_no_visit<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    loop_ids: &[HirId],
 +    ignore_locals: &HirIdSet,
 +) -> bool {
 +    match expr.kind {
 +        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
 +        | ExprKind::Continue(Destination { target_id: Ok(id), .. })
 +            if loop_ids.contains(&id) =>
 +        {
 +            true
 +        },
 +        ExprKind::Break(..)
 +        | ExprKind::Continue(_)
 +        | ExprKind::Ret(_)
 +        | ExprKind::Yield(..)
 +        | ExprKind::InlineAsm(_) => false,
 +        // Accessing a field of a local value can only be done if the type isn't
 +        // partially moved.
 +        ExprKind::Field(
 +            &Expr {
 +                hir_id,
 +                kind:
 +                    ExprKind::Path(QPath::Resolved(
 +                        _,
 +                        Path {
 +                            res: Res::Local(local_id),
 +                            ..
 +                        },
 +                    )),
 +                ..
 +            },
 +            _,
 +        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
 +            // TODO: check if the local has been partially moved. Assume it has for now.
 +            false
 +        },
 +        _ => true,
 +    }
 +}
 +
 +/// How a local is captured by a closure
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum CaptureKind {
 +    Value,
 +    Ref(Mutability),
 +}
 +impl CaptureKind {
 +    pub fn is_imm_ref(self) -> bool {
 +        self == Self::Ref(Mutability::Not)
 +    }
 +}
 +impl std::ops::BitOr for CaptureKind {
 +    type Output = Self;
 +    fn bitor(self, rhs: Self) -> Self::Output {
 +        match (self, rhs) {
 +            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
 +            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
 +            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
 +            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
 +        }
 +    }
 +}
 +impl std::ops::BitOrAssign for CaptureKind {
 +    fn bitor_assign(&mut self, rhs: Self) {
 +        *self = *self | rhs;
 +    }
 +}
 +
 +/// Given an expression referencing a local, determines how it would be captured in a closure.
 +/// Note as this will walk up to parent expressions until the capture can be determined it should
 +/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
 +/// function argument (other than a receiver).
 +pub fn capture_local_usage<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind {
 +    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
 +        let mut capture = CaptureKind::Ref(Mutability::Not);
 +        pat.each_binding_or_first(&mut |_, id, span, _| match cx
 +            .typeck_results()
 +            .extract_binding_mode(cx.sess(), id, span)
 +            .unwrap()
 +        {
 +            BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
 +                capture = CaptureKind::Value;
 +            },
 +            BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
 +                capture = CaptureKind::Ref(Mutability::Mut);
 +            },
 +            _ => (),
 +        });
 +        capture
 +    }
 +
 +    debug_assert!(matches!(
 +        e.kind,
 +        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
 +    ));
 +
 +    let mut child_id = e.hir_id;
 +    let mut capture = CaptureKind::Value;
 +    let mut capture_expr_ty = e;
 +
 +    for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
 +        if let [
 +            Adjustment {
 +                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
 +                target,
 +            },
 +            ref adjust @ ..,
 +        ] = *cx
 +            .typeck_results()
 +            .adjustments()
 +            .get(child_id)
 +            .map_or(&[][..], |x| &**x)
 +        {
 +            if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
 +                *adjust.last().map_or(target, |a| a.target).kind()
 +            {
 +                return CaptureKind::Ref(mutability);
 +            }
 +        }
 +
 +        match parent {
 +            Node::Expr(e) => match e.kind {
 +                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
 +                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
 +                ExprKind::Assign(lhs, ..) | ExprKind::Assign(_, lhs, _) if lhs.hir_id == child_id => {
 +                    return CaptureKind::Ref(Mutability::Mut);
 +                },
 +                ExprKind::Field(..) => {
 +                    if capture == CaptureKind::Value {
 +                        capture_expr_ty = e;
 +                    }
 +                },
 +                ExprKind::Let(let_expr) => {
 +                    let mutability = match pat_capture_kind(cx, let_expr.pat) {
 +                        CaptureKind::Value => Mutability::Not,
 +                        CaptureKind::Ref(m) => m,
 +                    };
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                ExprKind::Match(_, arms, _) => {
 +                    let mut mutability = Mutability::Not;
 +                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
 +                        match capture {
 +                            CaptureKind::Value => break,
 +                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
 +                            CaptureKind::Ref(Mutability::Not) => (),
 +                        }
 +                    }
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                _ => break,
 +            },
 +            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
 +                CaptureKind::Value => break,
 +                capture @ CaptureKind::Ref(_) => return capture,
 +            },
 +            _ => break,
 +        }
 +
 +        child_id = parent_id;
 +    }
 +
 +    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
 +        // Copy types are never automatically captured by value.
 +        CaptureKind::Ref(Mutability::Not)
 +    } else {
 +        capture
 +    }
 +}
 +
 +/// Checks if the expression can be moved into a closure as is. This will return a list of captures
 +/// if so, otherwise, `None`.
 +pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
 +    struct V<'cx, 'tcx> {
 +        cx: &'cx LateContext<'tcx>,
 +        // Stack of potential break targets contained in the expression.
 +        loops: Vec<HirId>,
 +        /// Local variables created in the expression. These don't need to be captured.
 +        locals: HirIdSet,
 +        /// Whether this expression can be turned into a closure.
 +        allow_closure: bool,
 +        /// Locals which need to be captured, and whether they need to be by value, reference, or
 +        /// mutable reference.
 +        captures: HirIdMap<CaptureKind>,
 +    }
 +    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
 +        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +            if !self.allow_closure {
 +                return;
 +            }
 +
 +            match e.kind {
 +                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
 +                    if !self.locals.contains(&l) {
 +                        let cap = capture_local_usage(self.cx, e);
 +                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
 +                    }
 +                },
 +                ExprKind::Closure(..) => {
 +                    let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id).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(kind) => match kind {
 +                                    BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
 +                                    BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
 +                                        CaptureKind::Ref(Mutability::Mut)
 +                                    },
 +                                },
 +                            };
 +                            self.captures
 +                                .entry(local_id)
 +                                .and_modify(|e| *e |= capture)
 +                                .or_insert(capture);
 +                        }
 +                    }
 +                },
 +                ExprKind::Loop(b, ..) => {
 +                    self.loops.push(e.hir_id);
 +                    self.visit_block(b);
 +                    self.loops.pop();
 +                },
 +                _ => {
 +                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
 +                    walk_expr(self, e);
 +                },
 +            }
 +        }
 +
 +        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
 +            p.each_binding_or_first(&mut |_, id, _, _| {
 +                self.locals.insert(id);
 +            });
 +        }
 +    }
 +
 +    let mut v = V {
 +        cx,
 +        allow_closure: true,
 +        loops: Vec::new(),
 +        locals: HirIdSet::default(),
 +        captures: HirIdMap::default(),
 +    };
 +    v.visit_expr(expr);
 +    v.allow_closure.then(|| 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, 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(path.ident.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);
 +    Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()
 +}
 +
 +/// Gets the name of the item the expression is in, if available.
 +pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
 +    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
 +    match cx.tcx.hir().find_by_def_id(parent_id) {
 +        Some(
 +            Node::Item(Item { ident, .. })
 +            | Node::TraitItem(TraitItem { ident, .. })
 +            | Node::ImplItem(ImplItem { ident, .. }),
 +        ) => Some(ident.name),
 +        _ => None,
 +    }
 +}
 +
 +pub struct ContainsName {
 +    pub name: Symbol,
 +    pub result: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ContainsName {
 +    fn visit_name(&mut self, _: Span, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +}
 +
 +/// Checks if an `Expr` contains a certain name.
 +pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
 +    let mut cn = ContainsName { name, result: false };
 +    cn.visit_expr(expr);
 +    cn.result
 +}
 +
 +/// Returns `true` if `expr` contains a return expression
 +pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    let mut found = false;
 +    expr_visitor_no_bodies(|expr| {
 +        if !found {
 +            if let hir::ExprKind::Ret(..) = &expr.kind {
 +                found = true;
 +            }
 +        }
 +        !found
 +    })
 +    .visit_expr(expr);
 +    found
 +}
 +
 +/// Extends the span to the beginning of the spans line, incl. whitespaces.
 +///
 +/// ```rust
 +///        let x = ();
 +/// //             ^^
 +/// // will be converted to
 +///        let x = ();
 +/// // ^^^^^^^^^^^^^^
 +/// ```
 +fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    let span = original_sp(span, DUMMY_SP);
 +    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
 +    let line_no = source_map_and_line.line;
 +    let line_start = source_map_and_line.sf.lines[line_no];
 +    span.with_lo(line_start)
 +}
 +
 +/// Gets the parent node, if any.
 +pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
 +    tcx.hir().parent_iter(id).next().map(|(_, node)| node)
 +}
 +
 +/// Gets the parent expression, if any –- this is useful to constrain a lint.
 +pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    get_parent_expr_for_hir(cx, e.hir_id)
 +}
 +
 +/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
 +/// constraint lints
 +pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
 +    match get_parent_node(cx.tcx, hir_id) {
 +        Some(Node::Expr(parent)) => Some(parent),
 +        _ => None,
 +    }
 +}
 +
 +pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
 +    let map = &cx.tcx.hir();
 +    let enclosing_node = map
 +        .get_enclosing_scope(hir_id)
 +        .and_then(|enclosing_id| map.find(enclosing_id));
 +    enclosing_node.and_then(|node| match node {
 +        Node::Block(block) => Some(block),
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(_, _, eid),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(_, eid),
 +            ..
 +        }) => match cx.tcx.hir().body(eid).value.kind {
 +            ExprKind::Block(block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Gets the loop or closure enclosing the given expression, if any.
 +pub fn get_enclosing_loop_or_closure<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
 +        match node {
 +            Node::Expr(
 +                e @ Expr {
 +                    kind: ExprKind::Loop(..) | ExprKind::Closure(..),
 +                    ..
 +                },
 +            ) => return Some(e),
 +            Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
 +            _ => break,
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets the parent node if it's an impl block.
 +pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
 +    match tcx.hir().parent_iter(id).next() {
 +        Some((
 +            _,
 +            Node::Item(Item {
 +                kind: ItemKind::Impl(imp),
 +                ..
 +            }),
 +        )) => Some(imp),
 +        _ => None,
 +    }
 +}
 +
 +/// Removes blocks around an expression, only if the block contains just one expression
 +/// and no statements. Unsafe blocks are not removed.
 +///
 +/// Examples:
 +///  * `{}`               -> `{}`
 +///  * `{ x }`            -> `x`
 +///  * `{{ x }}`          -> `x`
 +///  * `{ x; }`           -> `{ x; }`
 +///  * `{ x; y }`         -> `{ x; y }`
 +///  * `{ unsafe { x } }` -> `unsafe { x }`
 +pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
 +    while let ExprKind::Block(
 +        Block {
 +            stmts: [],
 +            expr: Some(inner),
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        },
 +        _,
 +    ) = expr.kind
 +    {
 +        expr = inner;
 +    }
 +    expr
 +}
 +
 +/// Removes blocks around an expression, only if the block contains just one expression
 +/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
 +///
 +/// Examples:
 +///  * `{}`               -> `{}`
 +///  * `{ x }`            -> `x`
 +///  * `{ x; }`           -> `x`
 +///  * `{{ x; }}`         -> `x`
 +///  * `{ x; y }`         -> `{ x; y }`
 +///  * `{ unsafe { x } }` -> `unsafe { x }`
 +pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
 +    while let ExprKind::Block(
 +        Block {
 +            stmts: [],
 +            expr: Some(inner),
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        }
 +        | Block {
 +            stmts:
 +                [
 +                    Stmt {
 +                        kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
 +                        ..
 +                    },
 +                ],
 +            expr: None,
 +            rules: BlockCheckMode::DefaultBlock,
 +            ..
 +        },
 +        _,
 +    ) = expr.kind
 +    {
 +        expr = inner;
 +    }
 +    expr
 +}
 +
 +/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
 +pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    let mut iter = tcx.hir().parent_iter(expr.hir_id);
 +    match iter.next() {
 +        Some((
 +            _,
 +            Node::Expr(Expr {
 +                kind: ExprKind::If(_, _, Some(else_expr)),
 +                ..
 +            }),
 +        )) => else_expr.hir_id == expr.hir_id,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks whether the given expression is a constant integer of the given value.
 +/// unlike `is_integer_literal`, this version does const folding
 +pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
 +    if is_integer_literal(e, value) {
 +        return true;
 +    }
 +    let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
 +    if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
 +        return value == v;
 +    }
 +    false
 +}
 +
 +/// Checks whether the given expression is a constant literal of the given value.
 +pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 +    // FIXME: use constant folding
 +    if let ExprKind::Lit(ref spanned) = expr.kind {
 +        if let LitKind::Int(v, _) = spanned.node {
 +            return v == value;
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if the given `Expr` has been coerced before.
 +///
 +/// Examples of coercions can be found in the Nomicon at
 +/// <https://doc.rust-lang.org/nomicon/coercions.html>.
 +///
 +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
 +/// information on adjustments and coercions.
 +pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    cx.typeck_results().adjustments().get(e.hir_id).is_some()
 +}
 +
 +/// Returns the pre-expansion span if this comes from an expansion of the
 +/// macro `name`.
 +/// See also [`is_direct_expn_of`].
 +#[must_use]
 +pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 +    loop {
 +        if span.from_expansion() {
 +            let data = span.ctxt().outer_expn_data();
 +            let new_span = data.call_site;
 +
 +            if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +                if mac_name.as_str() == name {
 +                    return Some(new_span);
 +                }
 +            }
 +
 +            span = new_span;
 +        } else {
 +            return None;
 +        }
 +    }
 +}
 +
 +/// Returns the pre-expansion span if the span directly comes from an expansion
 +/// of the macro `name`.
 +/// The difference with [`is_expn_of`] is that in
 +/// ```rust
 +/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
 +/// # macro_rules! bar { ($e:expr) => { $e } }
 +/// foo!(bar!(42));
 +/// ```
 +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 +/// from `bar!` by `is_direct_expn_of`.
 +#[must_use]
 +pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 +    if span.from_expansion() {
 +        let data = span.ctxt().outer_expn_data();
 +        let new_span = data.call_site;
 +
 +        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +            if mac_name.as_str() == name {
 +                return Some(new_span);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Convenience function to get the return type of a function.
 +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
 +    cx.tcx.erase_late_bound_regions(ret_ty)
 +}
 +
 +/// Convenience function to get the nth argument type of a function.
 +pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
 +    cx.tcx.erase_late_bound_regions(arg)
 +}
 +
 +/// Checks if an expression is constructing a tuple-like enum variant or struct
 +pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(fun, _) = expr.kind {
 +        if let ExprKind::Path(ref qp) = fun.kind {
 +            let res = cx.qpath_res(qp, fun.hir_id);
 +            return match res {
 +                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
 +                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
 +                _ => false,
 +            };
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if a pattern is refutable.
 +// TODO: should be implemented using rustc/mir_build/thir machinery
 +pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 +    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
 +        matches!(
 +            cx.qpath_res(qpath, id),
 +            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
 +        )
 +    }
 +
 +    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
 +        i.into_iter().any(|pat| is_refutable(cx, pat))
 +    }
 +
 +    match pat.kind {
 +        PatKind::Wild => false,
 +        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
 +        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
 +        PatKind::Lit(..) | PatKind::Range(..) => true,
 +        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
 +        PatKind::Or(pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats)
 +        },
 +        PatKind::Tuple(pats, _) => are_refutable(cx, pats),
 +        PatKind::Struct(ref qpath, fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
 +        PatKind::Slice(head, middle, tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind() {
 +                rustc_ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
 +/// the function once on the given pattern.
 +pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
 +    if let PatKind::Or(pats) = pat.kind {
 +        pats.iter().for_each(f);
 +    } else {
 +        f(pat);
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    has_attr(attrs, sym::automatically_derived)
 +}
 +
 +pub fn is_self(slf: &Param<'_>) -> bool {
 +    if let PatKind::Binding(.., name, _) = slf.pat.kind {
 +        name.name == kw::SelfLower
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
 +        if let Res::SelfTy { .. } = path.res {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
 +    (0..decl.inputs.len()).map(move |i| &body.params[i])
 +}
 +
 +/// Checks if a given expression is a match expression expanded from the `?`
 +/// operator or the `try` macro.
 +pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
 +            if is_lang_ctor(cx, path, ResultOk);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if path_to_local_id(arm.body, hir_id);
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            is_lang_ctor(cx, path, ResultErr)
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
 +        if *source == MatchSource::TryDesugar {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
 +            then {
 +                return Some(expr);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Returns `true` if the lint is allowed in the current context
 +///
 +/// Useful for skipping long running code when it's unnecessary
 +pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
 +    while let PatKind::Ref(subpat, _) = pat.kind {
 +        pat = subpat;
 +    }
 +    pat
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
 +    Integer::from_int_ty(&tcx, ity).size().bits()
 +}
 +
 +#[allow(clippy::cast_possible_wrap)]
 +/// Turn a constant int byte representation into an i128
 +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as i128) << amt) >> amt
 +}
 +
 +#[allow(clippy::cast_sign_loss)]
 +/// clip unused bytes
 +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as u128) << amt) >> amt
 +}
 +
 +/// clip unused bytes
 +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
 +    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +pub fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(symbol))
 +}
 +
 +pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
 +    let map = &tcx.hir();
 +    let mut prev_enclosing_node = None;
 +    let mut enclosing_node = node;
 +    while Some(enclosing_node) != prev_enclosing_node {
 +        if has_attr(map.attrs(enclosing_node), symbol) {
 +            return true;
 +        }
 +        prev_enclosing_node = Some(enclosing_node);
 +        enclosing_node = map.local_def_id_to_hir_id(map.get_parent_item(enclosing_node));
 +    }
 +
 +    false
 +}
 +
 +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
 +    any_parent_has_attr(tcx, node, sym::automatically_derived)
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
 +/// ```
 +pub fn match_function_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    path: &[&str],
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        if match_def_path(cx, fun_def_id, path);
 +        then {
 +            return Some(args);
 +        }
 +    };
 +    None
 +}
 +
 +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 +/// any.
 +///
 +/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
 +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
 +    let search_path = cx.get_def_path(did);
 +    paths
 +        .iter()
 +        .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
 +}
 +
 +/// Checks if the given `DefId` matches the path.
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
 +    // We should probably move to Symbols in Clippy as well rather than interning every time.
 +    let path = cx.get_def_path(did);
 +    syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
 +}
 +
 +/// Checks if the given `DefId` matches the `libc` item.
 +pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
 +    let path = cx.get_def_path(did);
 +    // libc is meant to be used as a flat list of names, but they're all actually defined in different
 +    // modules based on the target platform. Ignore everything but crate name and the item name.
 +    path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
 +}
 +
 +/// 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>(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)),
 +        _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
 +    }
 +}
 +
 +/// Gets the node where an expression is either used, or it's type is unified with another branch.
 +/// Returns both the node and the `HirId` of the closest child node.
 +pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
 +    let mut child_id = expr.hir_id;
 +    let mut iter = tcx.hir().parent_iter(child_id);
 +    loop {
 +        match iter.next() {
 +            None => break None,
 +            Some((id, Node::Block(_))) => child_id = id,
 +            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
 +            Some((_, Node::Expr(expr))) => match expr.kind {
 +                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
 +                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
 +                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
 +                _ => break Some((Node::Expr(expr), child_id)),
 +            },
 +            Some((_, node)) => break Some((node, child_id)),
 +        }
 +    }
 +}
 +
 +/// Checks if the result of an expression is used, or it's type is unified with another branch.
 +pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    !matches!(
 +        get_expr_use_or_unification_node(tcx, expr),
 +        None | Some((
 +            Node::Stmt(Stmt {
 +                kind: StmtKind::Expr(_)
 +                    | StmtKind::Semi(_)
 +                    | StmtKind::Local(Local {
 +                        pat: Pat {
 +                            kind: PatKind::Wild,
 +                            ..
 +                        },
 +                        ..
 +                    }),
 +                ..
 +            }),
 +            _
 +        ))
 +    )
 +}
 +
 +/// Checks if the expression is the final expression returned from a block.
 +pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
 +}
 +
 +pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
 +    if !is_no_std_crate(cx) {
 +        Some("std")
 +    } else if !is_no_core_crate(cx) {
 +        Some("core")
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr.path == sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr.path == sym::no_core
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
 +/// ```rust
 +/// # struct S;
 +/// # trait Trait { fn f(); }
 +/// impl Trait for S {
 +///     fn f() {}
 +/// }
 +/// ```
 +pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
 +        matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates = cx
 +        .tcx
 +        .predicates_of(did)
 +        .predicates
 +        .iter()
 +        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
 +    traits::impossible_predicates(
 +        cx.tcx,
 +        traits::elaborate_predicates(cx.tcx, predicates)
 +            .map(|o| o.predicate)
 +            .collect::<Vec<_>>(),
 +    )
 +}
 +
 +/// Returns the `DefId` of the callee if the given expression is a function or method call.
 +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 +    match &expr.kind {
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(qpath),
 +                hir_id: path_hir_id,
 +                ..
 +            },
 +            ..,
 +        ) => 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().nth(1).unwrap().expect_ty().kind() {
 +            rustc_ty::Slice(..) => return Some("slice".into()),
 +            rustc_ty::Array(..) => return Some("array".into()),
 +            rustc_ty::Tuple(..) => return Some("tuple".into()),
 +            _ => {
 +                // is_recursively_primitive_type() should have taken care
 +                // of the rest and we can rely on the type that is found
 +                let refs_peeled = expr_type.peel_refs();
 +                return Some(refs_peeled.walk().last().unwrap().to_string());
 +            },
 +        }
 +    }
 +    None
 +}
 +
 +/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
 +/// `hash` must be comformed with `eq`
 +pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 +where
 +    Hash: Fn(&T) -> u64,
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    match exprs {
 +        [a, b] if eq(a, b) => return vec![(a, b)],
 +        _ if exprs.len() <= 2 => return vec![],
 +        _ => {},
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: UnhashMap<u64, Vec<&_>> =
 +        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 +
 +    for expr in exprs {
 +        match map.entry(hash(expr)) {
 +            Entry::Occupied(mut o) => {
 +                for o in o.get() {
 +                    if eq(o, expr) {
 +                        match_expr_list.push((o, expr));
 +                    }
 +                }
 +                o.get_mut().push(expr);
 +            },
 +            Entry::Vacant(v) => {
 +                v.insert(vec![expr]);
 +            },
 +        }
 +    }
 +
 +    match_expr_list
 +}
 +
 +/// Peels off all references on the pattern. Returns the underlying pattern and the number of
 +/// references removed.
 +pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
 +        if let PatKind::Ref(pat, _) = pat.kind {
 +            peel(pat, count + 1)
 +        } else {
 +            (pat, count)
 +        }
 +    }
 +    peel(pat, 0)
 +}
 +
 +/// Peels of expressions while the given closure returns `Some`.
 +pub fn peel_hir_expr_while<'tcx>(
 +    mut expr: &'tcx Expr<'tcx>,
 +    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
 +) -> &'tcx Expr<'tcx> {
 +    while let Some(e) = f(expr) {
 +        expr = e;
 +    }
 +    expr
 +}
 +
 +/// Peels off up to the given number of references on the expression. Returns the underlying
 +/// expression and the number of references removed.
 +pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
 +    let mut remaining = count;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
 +            remaining -= 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count - remaining)
 +}
 +
 +/// Peels off all references on the expression. Returns the underlying expression and the number of
 +/// references removed.
 +pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
 +    let mut count = 0;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
 +            count += 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count)
 +}
 +
 +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 +pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 +    loop {
 +        match expr.kind {
 +            ExprKind::AddrOf(_, _, e) => expr = e,
 +            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +        if let Res::Def(_, def_id) = path.res {
 +            return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
 +        }
 +    }
 +    false
 +}
 +
 +struct TestItemNamesVisitor<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +    names: Vec<Symbol>,
 +}
 +
 +impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> {
 +    fn visit_item(&mut self, item: &Item<'_>) {
 +        if let ItemKind::Const(ty, _body) = item.kind {
 +            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +                // We could also check for the type name `test::TestDescAndFn`
 +                if let Res::Def(DefKind::Struct, _) = path.res {
 +                    let has_test_marker = self
 +                        .tcx
 +                        .hir()
 +                        .attrs(item.hir_id())
 +                        .iter()
 +                        .any(|a| a.has_name(sym::rustc_test_marker));
 +                    if has_test_marker {
 +                        self.names.push(item.ident.name);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
 +    fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
 +    fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
 +}
 +
 +static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
 +
 +fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
 +    let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
 +    let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
 +    match map.entry(module) {
 +        Entry::Occupied(entry) => f(entry.get()),
 +        Entry::Vacant(entry) => {
 +            let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
 +            tcx.hir().visit_item_likes_in_module(module, &mut visitor);
 +            visitor.names.sort_unstable();
 +            f(&*entry.insert(visitor.names))
 +        },
 +    }
 +}
 +
 +/// Checks if the function containing the given `HirId` is a `#[test]` function
 +///
 +/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 +    with_test_item_names(tcx, tcx.parent_module(id), |names| {
 +        tcx.hir()
 +            .parent_iter(id)
 +            // Since you can nest functions we need to collect all until we leave
 +            // function scope
 +            .any(|(_id, node)| {
 +                if let Node::Item(item) = node {
 +                    if let ItemKind::Fn(_, _, _) = item.kind {
 +                        // Note that we have sorted the item names in the visitor,
 +                        // so the binary_search gets the same as `contains`, but faster.
 +                        return names.binary_search(&item.ident.name).is_ok();
 +                    }
 +                }
 +                false
 +            })
 +    })
 +}
 +
 +/// Checks whether item either has `test` attribute applied, or
 +/// is a module with `test` in its name.
 +///
 +/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
 +    is_in_test_function(tcx, item.hir_id())
 +        || matches!(item.kind, ItemKind::Mod(..))
 +            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 +}
 +
 +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 fce93153d96ec1841eae99b5ec3b584e22c2e261,0000000000000000000000000000000000000000..0424e06720263e5322b38eabf54d518bb899d0e6
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,35 @@@
-     1,51,0 { BORROW_AS_PTR }
 +use rustc_semver::RustcVersion;
 +
 +macro_rules! msrv_aliases {
 +    ($($major:literal,$minor:literal,$patch:literal {
 +        $($name:ident),* $(,)?
 +    })*) => {
 +        $($(
 +        pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch);
 +        )*)*
 +    };
 +}
 +
 +// names may refer to stabilized feature flags or library items
 +msrv_aliases! {
 +    1,53,0 { OR_PATTERNS, MANUAL_BITS }
 +    1,52,0 { STR_SPLIT_ONCE }
-     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
++    1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS }
 +    1,50,0 { BOOL_THEN }
 +    1,47,0 { TAU }
 +    1,46,0 { CONST_IF_MATCH }
 +    1,45,0 { STR_STRIP_PREFIX }
 +    1,43,0 { LOG2_10, LOG10_2 }
 +    1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
 +    1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
 +    1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
 +    1,38,0 { POINTER_CAST }
 +    1,37,0 { TYPE_ALIAS_ENUM_VARIANTS }
 +    1,36,0 { ITERATOR_COPIED }
 +    1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
 +    1,34,0 { TRY_FROM }
 +    1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
 +    1,28,0 { FROM_BOOL }
++    1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
 +    1,16,0 { STR_REPEAT }
 +}
index 6f56f8d51365a9407e2a36ce6205ac6a1719c789,0000000000000000000000000000000000000000..79e6e92dc0aaf3a2506db51edaeaf6cc47fcb1df
mode 100644,000000..100644
--- /dev/null
@@@ -1,179 -1,0 +1,181 @@@
 +//! This module contains paths to types and functions Clippy needs to know
 +//! about.
 +//!
 +//! Whenever possible, please consider diagnostic items over hardcoded paths.
 +//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 +
 +#[cfg(feature = "internal")]
 +pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
 +#[cfg(feature = "internal")]
 +pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
 +    ["rustc_lint_defs", "Applicability", "Unspecified"],
 +    ["rustc_lint_defs", "Applicability", "HasPlaceholders"],
 +    ["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
 +    ["rustc_lint_defs", "Applicability", "MachineApplicable"],
 +];
 +#[cfg(feature = "internal")]
 +pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
 +pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
 +pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
 +pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
 +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 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"];
 +#[cfg(feature = "internal")]
 +pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
 +#[cfg(feature = "internal")]
 +pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
 +pub const EXIT: [&str; 3] = ["std", "process", "exit"];
 +pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
 +pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
 +pub const 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_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"];
 +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
 +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
 +pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
 +pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 +pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
 +#[cfg(feature = "internal")]
 +pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 +#[cfg(feature = "internal")]
 +pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 +pub const 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")]
 +pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
 +#[cfg(feature = "internal")]
 +pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
 +#[cfg(feature = "internal")]
 +pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
 +#[cfg(feature = "internal")]
 +pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
 +pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
 +pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
 +/// 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 const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"];
 +pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"];
 +pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
 +pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
 +pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
 +pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 +pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 +pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
 +#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
 +pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
 +pub const 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_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"];
++pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"];
 +pub const PTR_WRITE: [&str; 3] = ["core", "ptr", "write"];
 +pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
 +pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"];
 +pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"];
 +pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 +pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 +pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 +pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 +pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
 +#[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"];
 +#[cfg(feature = "internal")]
 +pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
 +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")]
 +pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
 +#[cfg(feature = "internal")]
 +pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
 +#[cfg(feature = "internal")]
 +pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 +#[cfg(feature = "internal")]
 +pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 +pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 +pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
 +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 +pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
 +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 +pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
 +pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 +pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 +pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
 +pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 +pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 +pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 +pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
index afe3033c288cffd8d95b06ea2e833989455cb81a,0000000000000000000000000000000000000000..c4f8f989384280659f899f6f6d9820cf0087e8a6
mode 100644,000000..100644
--- /dev/null
@@@ -1,124 -1,0 +1,145 @@@
 +# Release a new Clippy Version
 +
 +_NOTE: This document is probably only relevant to you, if you're a member of the
 +Clippy team._
 +
 +Clippy is released together with stable Rust releases. The dates for these
 +releases can be found at the [Rust Forge]. This document explains the necessary
 +steps to create a Clippy release.
 +
 +1. [Remerge the `beta` branch](#remerge-the-beta-branch)
 +2. [Update the `beta` branch](#update-the-beta-branch)
 +3. [Find the Clippy commit](#find-the-clippy-commit)
 +4. [Tag the stable commit](#tag-the-stable-commit)
 +5. [Update `CHANGELOG.md`](#update-changelogmd)
 +
 +_NOTE: This document is for stable Rust releases, not for point releases. For
 +point releases, step 1. and 2. should be enough._
 +
 +[Rust Forge]: https://forge.rust-lang.org/
 +
 +
 +## Remerge the `beta` branch
 +
 +This step is only necessary, if since the last release something was backported
 +to the beta Rust release. The remerge is then necessary, to make sure that the
 +Clippy commit, that was used by the now stable Rust release, persists in the
 +tree of the Clippy repository.
 +
 +To find out if this step is necessary run
 +
 +```bash
 +# Assumes that the local master branch is up-to-date
 +$ git fetch upstream
 +$ git branch master --contains upstream/beta
 +```
 +
 +If this command outputs `master`, this step is **not** necessary.
 +
 +```bash
 +# Assuming `HEAD` is the current `master` branch of rust-lang/rust-clippy
 +$ git checkout -b backport_remerge
 +$ git merge upstream/beta
 +$ git diff  # This diff has to be empty, otherwise something with the remerge failed
 +$ git push origin backport_remerge  # This can be pushed to your fork
 +```
 +
 +After this, open a PR to the master branch. In this PR, the commit hash of the
 +`HEAD` of the `beta` branch must exists. In addition to that, no files should
 +be changed by this PR.
 +
 +
 +## Update the `beta` branch
 +
 +This step must be done **after** the PR of the previous step was merged.
 +
 +First, the Clippy commit of the `beta` branch of the Rust repository has to be
 +determined.
 +
 +```bash
 +# Assuming the current directory corresponds to the Rust repository
 +$ git checkout beta
 +$ BETA_SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g")
 +```
 +
 +After finding the Clippy commit, the `beta` branch in the Clippy repository can
 +be updated.
 +
 +```bash
 +# Assuming the current directory corresponds to the Clippy repository
 +$ git checkout beta
 +$ git reset --hard $BETA_SHA
 +$ git push upstream beta
 +```
 +
 +
 +## Find the Clippy commit
 +
 +The first step is to tag the Clippy commit, that is included in the stable Rust
 +release. This commit can be found in the Rust repository.
 +
 +```bash
 +# Assuming the current directory corresponds to the Rust repository
 +$ git fetch upstream    # `upstream` is the `rust-lang/rust` remote
 +$ git checkout 1.XX.0   # XX should be exchanged with the corresponding version
 +$ SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g")
 +```
 +
 +
 +## Tag the stable commit
 +
 +After finding the Clippy commit, it can be tagged with the release number.
 +
 +```bash
 +# Assuming the current directory corresponds to the Clippy repository
 +$ git checkout $SHA
 +$ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
 +$ git push upstream rust-1.XX.0     # `upstream` is the `rust-lang/rust-clippy` remote
 +```
 +
 +After this, the release should be available on the Clippy [release page].
 +
 +[release page]: https://github.com/rust-lang/rust-clippy/releases
 +
 +## Update the `stable` branch
 +
 +At this step you should have already checked out the commit of the `rust-1.XX.0`
 +tag. Updating the stable branch from here is as easy as:
 +
 +```bash
 +# Assuming the current directory corresponds to the Clippy repository and the
 +# commit of the just created rust-1.XX.0 tag is checked out.
 +$ git push upstream rust-1.XX.0:stable  # `upstream` is the `rust-lang/rust-clippy` remote
 +```
 +
 +_NOTE: Usually there are no stable backports for Clippy, so this update should
 +be possible without force pushing or anything like this. If there should have
 +happened a stable backport, make sure to re-merge those changes just as with the
 +`beta` branch._
 +
 +## Update `CHANGELOG.md`
 +
 +For this see the document on [how to update the changelog].
 +
++If you don't have time to do a complete changelog update right away, just update
++the following parts:
++
++- Remove the `(beta)` from the new stable version:
++
++  ```markdown
++  ## Rust 1.XX (beta) -> ## Rust 1.XX
++  ```
++
++- Update the release date line of the new stable version:
++
++  ```markdown
++  Current beta, release 20YY-MM-DD -> Current stable, released 20YY-MM-DD
++  ```
++
++- Update the release date line of the previous stable version:
++
++  ```markdown
++  Current stable, released 20YY-MM-DD -> Released 20YY-MM-DD
++  ```
++
 +[how to update the changelog]: https://github.com/rust-lang/rust-clippy/blob/master/doc/changelog_update.md
index 5befb856a023470c0e211f281807f65a6fa17fa3,0000000000000000000000000000000000000000..bb29c71e9f455889ff8cb1f001ee916fb273b0c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2022-03-24"
 +[toolchain]
++channel = "nightly-2022-04-07"
 +components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index bc1b0d7457559da68ddfdf3f964ed6f59018551e,0000000000000000000000000000000000000000..00dc916b217ca0b93f18a387290545e517a2a97f
mode 100644,000000..100644
--- /dev/null
@@@ -1,352 -1,0 +1,351 @@@
-     let fallback_bundle = rustc_errors::fallback_fluent_bundle(false)
-         .expect("failed to load fallback fluent bundle");
 +#![feature(rustc_private)]
 +#![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)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_driver;
 +extern crate rustc_errors;
 +extern crate rustc_interface;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +
 +use rustc_interface::interface;
 +use rustc_session::parse::ParseSess;
 +use rustc_span::symbol::Symbol;
 +use rustc_tools_util::VersionInfo;
 +
 +use std::borrow::Cow;
 +use std::env;
 +use std::lazy::SyncLazy;
 +use std::ops::Deref;
 +use std::panic;
 +use std::path::{Path, PathBuf};
 +use std::process::{exit, Command};
 +
 +/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 +/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
 +fn arg_value<'a, T: Deref<Target = str>>(
 +    args: &'a [T],
 +    find_arg: &str,
 +    pred: impl Fn(&str) -> bool,
 +) -> Option<&'a str> {
 +    let mut args = args.iter().map(Deref::deref);
 +    while let Some(arg) = args.next() {
 +        let mut arg = arg.splitn(2, '=');
 +        if arg.next() != Some(find_arg) {
 +            continue;
 +        }
 +
 +        match arg.next().or_else(|| args.next()) {
 +            Some(v) if pred(v) => return Some(v),
 +            _ => {},
 +        }
 +    }
 +    None
 +}
 +
 +#[test]
 +fn test_arg_value() {
 +    let args = &["--bar=bar", "--foobar", "123", "--foo"];
 +
 +    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
 +    assert_eq!(arg_value(args, "--bar", |_| false), None);
 +    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
 +    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
 +    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
 +    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
 +    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
 +    assert_eq!(arg_value(args, "--foo", |_| true), None);
 +}
 +
 +fn track_clippy_args(parse_sess: &mut ParseSess, args_env_var: &Option<String>) {
 +    parse_sess.env_depinfo.get_mut().insert((
 +        Symbol::intern("CLIPPY_ARGS"),
 +        args_env_var.as_deref().map(Symbol::intern),
 +    ));
 +}
 +
 +struct DefaultCallbacks;
 +impl rustc_driver::Callbacks for DefaultCallbacks {}
 +
 +/// This is different from `DefaultCallbacks` that it will inform Cargo to track the value of
 +/// `CLIPPY_ARGS` environment variable.
 +struct RustcCallbacks {
 +    clippy_args_var: Option<String>,
 +}
 +
 +impl rustc_driver::Callbacks for RustcCallbacks {
 +    fn config(&mut self, config: &mut interface::Config) {
 +        let clippy_args_var = self.clippy_args_var.take();
 +        config.parse_sess_created = Some(Box::new(move |parse_sess| {
 +            track_clippy_args(parse_sess, &clippy_args_var);
 +        }));
 +    }
 +}
 +
 +struct ClippyCallbacks {
 +    clippy_args_var: Option<String>,
 +}
 +
 +impl rustc_driver::Callbacks for ClippyCallbacks {
 +    fn config(&mut self, config: &mut interface::Config) {
 +        let previous = config.register_lints.take();
 +        let clippy_args_var = self.clippy_args_var.take();
 +        config.parse_sess_created = Some(Box::new(move |parse_sess| {
 +            track_clippy_args(parse_sess, &clippy_args_var);
 +        }));
 +        config.register_lints = Some(Box::new(move |sess, lint_store| {
 +            // technically we're ~guaranteed that this is none but might as well call anything that
 +            // is there already. Certainly it can't hurt.
 +            if let Some(previous) = &previous {
 +                (previous)(sess, lint_store);
 +            }
 +
 +            let conf = clippy_lints::read_conf(sess);
 +            clippy_lints::register_plugins(lint_store, sess, &conf);
 +            clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
 +            clippy_lints::register_renamed(lint_store);
 +        }));
 +
 +        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
 +        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
 +        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
 +        // use for Clippy.
 +        config.opts.debugging_opts.mir_opt_level = Some(0);
 +    }
 +}
 +
 +fn display_help() {
 +    println!(
 +        "\
 +Checks a package to catch common mistakes and improve your Rust code.
 +
 +Usage:
 +    cargo clippy [options] [--] [<opts>...]
 +
 +Common options:
 +    -h, --help               Print this message
 +        --rustc              Pass all args to rustc
 +    -V, --version            Print version info and exit
 +
 +Other options are the same as `cargo check`.
 +
 +To allow or deny a lint from the command line you can use `cargo clippy --`
 +with:
 +
 +    -W --warn OPT       Set lint warnings
 +    -A --allow OPT      Set lint allowed
 +    -D --deny OPT       Set lint denied
 +    -F --forbid OPT     Set lint forbidden
 +
 +You can use tool lints to allow or deny lints from your code, eg.:
 +
 +    #[allow(clippy::needless_lifetimes)]
 +"
 +    );
 +}
 +
 +const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
 +
 +static ICE_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = SyncLazy::new(|| {
 +    let hook = panic::take_hook();
 +    panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
 +    hook
 +});
 +
 +fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 +    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
 +    (*ICE_HOOK)(info);
 +
 +    // Separate the output with an empty line
 +    eprintln!();
 +
++    let fallback_bundle = rustc_errors::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
 +    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
 +        rustc_errors::ColorConfig::Auto,
 +        None,
 +        None,
 +        fallback_bundle,
 +        false,
 +        false,
 +        None,
 +        false,
 +    ));
 +    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
 +
 +    // a .span_bug or .bug call has already printed what
 +    // it wants to print.
 +    if !info.payload().is::<rustc_errors::ExplicitBug>() {
 +        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
 +        handler.emit_diagnostic(&mut d);
 +    }
 +
 +    let version_info = rustc_tools_util::get_version_info!();
 +
 +    let xs: Vec<Cow<'static, str>> = vec![
 +        "the compiler unexpectedly panicked. this is a bug.".into(),
 +        format!("we would appreciate a bug report: {}", bug_report_url).into(),
 +        format!("Clippy version: {}", version_info).into(),
 +    ];
 +
 +    for note in &xs {
 +        handler.note_without_error(note.as_ref());
 +    }
 +
 +    // If backtraces are enabled, also print the query stack
 +    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
 +
 +    let num_frames = if backtrace { None } else { Some(2) };
 +
 +    interface::try_print_query_stack(&handler, num_frames);
 +}
 +
 +fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> {
 +    home.and_then(|home| {
 +        toolchain.map(|toolchain| {
 +            let mut path = PathBuf::from(home);
 +            path.push("toolchains");
 +            path.push(toolchain);
 +            path
 +        })
 +    })
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +pub fn main() {
 +    rustc_driver::init_rustc_env_logger();
 +    SyncLazy::force(&ICE_HOOK);
 +    exit(rustc_driver::catch_with_exit_code(move || {
 +        let mut orig_args: Vec<String> = env::args().collect();
 +
 +        // Get the sysroot, looking from most specific to this invocation to the least:
 +        // - command line
 +        // - runtime environment
 +        //    - SYSROOT
 +        //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
 +        // - sysroot from rustc in the path
 +        // - compile-time environment
 +        //    - SYSROOT
 +        //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
 +        let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
 +        let have_sys_root_arg = sys_root_arg.is_some();
 +        let sys_root = sys_root_arg
 +            .map(PathBuf::from)
 +            .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
 +            .or_else(|| {
 +                let home = std::env::var("RUSTUP_HOME")
 +                    .or_else(|_| std::env::var("MULTIRUST_HOME"))
 +                    .ok();
 +                let toolchain = std::env::var("RUSTUP_TOOLCHAIN")
 +                    .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN"))
 +                    .ok();
 +                toolchain_path(home, toolchain)
 +            })
 +            .or_else(|| {
 +                Command::new("rustc")
 +                    .arg("--print")
 +                    .arg("sysroot")
 +                    .output()
 +                    .ok()
 +                    .and_then(|out| String::from_utf8(out.stdout).ok())
 +                    .map(|s| PathBuf::from(s.trim()))
 +            })
 +            .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
 +            .or_else(|| {
 +                let home = option_env!("RUSTUP_HOME")
 +                    .or(option_env!("MULTIRUST_HOME"))
 +                    .map(ToString::to_string);
 +                let toolchain = option_env!("RUSTUP_TOOLCHAIN")
 +                    .or(option_env!("MULTIRUST_TOOLCHAIN"))
 +                    .map(ToString::to_string);
 +                toolchain_path(home, toolchain)
 +            })
 +            .map(|pb| pb.to_string_lossy().to_string())
 +            .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
 +
 +        // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
 +        // for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
 +        // uses
 +        if let Some(pos) = orig_args.iter().position(|arg| arg == "--rustc") {
 +            orig_args.remove(pos);
 +            orig_args[0] = "rustc".to_string();
 +
 +            // if we call "rustc", we need to pass --sysroot here as well
 +            let mut args: Vec<String> = orig_args.clone();
 +            if !have_sys_root_arg {
 +                args.extend(vec!["--sysroot".into(), sys_root]);
 +            };
 +
 +            return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
 +        }
 +
 +        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
 +            let version_info = rustc_tools_util::get_version_info!();
 +            println!("{}", version_info);
 +            exit(0);
 +        }
 +
 +        // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
 +        // We're invoking the compiler programmatically, so we ignore this/
 +        let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
 +
 +        if wrapper_mode {
 +            // we still want to be able to invoke it normally though
 +            orig_args.remove(1);
 +        }
 +
 +        if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
 +            display_help();
 +            exit(0);
 +        }
 +
 +        // this conditional check for the --sysroot flag is there so users can call
 +        // `clippy_driver` directly
 +        // without having to pass --sysroot or anything
 +        let mut args: Vec<String> = orig_args.clone();
 +        if !have_sys_root_arg {
 +            args.extend(vec!["--sysroot".into(), sys_root]);
 +        };
 +
 +        let mut no_deps = false;
 +        let clippy_args_var = env::var("CLIPPY_ARGS").ok();
 +        let clippy_args = clippy_args_var
 +            .as_deref()
 +            .unwrap_or_default()
 +            .split("__CLIPPY_HACKERY__")
 +            .filter_map(|s| match s {
 +                "" => None,
 +                "--no-deps" => {
 +                    no_deps = true;
 +                    None
 +                },
 +                _ => Some(s.to_string()),
 +            })
 +            .chain(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()])
 +            .collect::<Vec<String>>();
 +
 +        // We enable Clippy if one of the following conditions is met
 +        // - IF Clippy is run on its test suite OR
 +        // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
 +        //    - IF `--no-deps` is not set (`!no_deps`) OR
 +        //    - IF `--no-deps` is set and Clippy is run on the specified primary package
 +        let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some();
 +        let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 +
 +        let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
 +        if clippy_enabled {
 +            args.extend(clippy_args);
 +        }
 +
 +        if clippy_enabled {
 +            rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run()
 +        } else {
 +            rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run()
 +        }
 +    }))
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0defd45b68b064745537b02321f5bb2b56c688aa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++#![cfg_attr(feature = "deny-warnings", deny(warnings))]
++#![warn(rust_2018_idioms, unused_lifetimes)]
++
++use std::path::PathBuf;
++use std::process::Command;
++
++#[test]
++fn fmt() {
++    if option_env!("RUSTC_TEST_SUITE").is_some() || option_env!("NO_FMT_TEST").is_some() {
++        return;
++    }
++
++    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
++    let output = Command::new("cargo")
++        .current_dir(root_dir)
++        .args(&["dev", "fmt", "--check"])
++        .output()
++        .unwrap();
++
++    println!("status: {}", output.status);
++    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
++    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
++
++    assert!(
++        output.status.success(),
++        "Formatting check failed. Run `cargo dev fmt` to update formatting."
++    );
++}
index af4c298b310852bf997a072838f58a71efcfe3fb,0000000000000000000000000000000000000000..e2010e9981315a748fbdbebc0a902bfa479766cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
- error: `mod.rs` files are required, found `/bad/inner.rs`
++error: `mod.rs` files are required, found `bad/inner.rs`
 +  --> $DIR/bad/inner.rs:1:1
 +   |
 +LL | pub mod stuff;
 +   | ^
 +   |
 +   = note: `-D clippy::self-named-module-files` implied by `-D warnings`
-    = help: move `/bad/inner.rs` to `/bad/inner/mod.rs`
++   = help: move `bad/inner.rs` to `bad/inner/mod.rs`
 +
- error: `mod.rs` files are required, found `/bad/inner/stuff.rs`
++error: `mod.rs` files are required, found `bad/inner/stuff.rs`
 +  --> $DIR/bad/inner/stuff.rs:1:1
 +   |
 +LL | pub mod most;
 +   | ^
 +   |
-    = help: move `/bad/inner/stuff.rs` to `/bad/inner/stuff/mod.rs`
++   = help: move `bad/inner/stuff.rs` to `bad/inner/stuff/mod.rs`
 +
 +error: aborting due to 2 previous errors
 +
index 11e15db7fb96b47829251b95126dae9af8791466,0000000000000000000000000000000000000000..f91940209383ff66d330c58df0e1ea54ca3d83b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
- error: `mod.rs` files are not allowed, found `/bad/mod.rs`
++error: `mod.rs` files are not allowed, found `bad/mod.rs`
 +  --> $DIR/bad/mod.rs:1:1
 +   |
 +LL | pub struct Thing;
 +   | ^
 +   |
 +   = note: `-D clippy::mod-module-files` implied by `-D warnings`
-    = help: move `/bad/mod.rs` to `/bad.rs`
++   = help: move `bad/mod.rs` to `bad.rs`
 +
 +error: aborting due to previous error
 +
index 9302e02ccb9c4f1a203dca9d0c4ad19cd430f919,0000000000000000000000000000000000000000..67e1a07b7f5fac8a895d8c224599facaa0225516
mode 100644,000000..100644
--- /dev/null
@@@ -1,73 -1,0 +1,68 @@@
- note: the lint level is defined here
-   --> $DIR/check_clippy_version_attribute.rs:1:9
-    |
- LL | #![deny(clippy::internal)]
-    |         ^^^^^^^^^^^^^^^^
 +error: this item has an invalid `clippy::version` attribute
 +  --> $DIR/check_clippy_version_attribute.rs:40:1
 +   |
 +LL | / declare_tool_lint! {
 +LL | |     #[clippy::version = "1.2.3.4.5.6"]
 +LL | |     pub clippy::INVALID_ONE,
 +LL | |     Warn,
 +LL | |     "One",
 +LL | |     report_in_external_macro: true
 +LL | | }
 +   | |_^
 +   |
 +note: the lint level is defined here
 +  --> $DIR/check_clippy_version_attribute.rs:1:9
 +   |
 +LL | #![deny(clippy::internal)]
 +   |         ^^^^^^^^^^^^^^^^
 +   = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
 +   = help: please use a valid sematic version, see `doc/adding_lints.md`
 +   = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: this item has an invalid `clippy::version` attribute
 +  --> $DIR/check_clippy_version_attribute.rs:48:1
 +   |
 +LL | / declare_tool_lint! {
 +LL | |     #[clippy::version = "I'm a string"]
 +LL | |     pub clippy::INVALID_TWO,
 +LL | |     Warn,
 +LL | |     "Two",
 +LL | |     report_in_external_macro: true
 +LL | | }
 +   | |_^
 +   |
 +   = help: please use a valid sematic version, see `doc/adding_lints.md`
 +   = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: this lint is missing the `clippy::version` attribute or version value
 +  --> $DIR/check_clippy_version_attribute.rs:59:1
 +   |
 +LL | / declare_tool_lint! {
 +LL | |     #[clippy::version]
 +LL | |     pub clippy::MISSING_ATTRIBUTE_ONE,
 +LL | |     Warn,
 +LL | |     "Two",
 +LL | |     report_in_external_macro: true
 +LL | | }
 +   | |_^
 +   |
 +   = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
 +   = help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
 +   = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: this lint is missing the `clippy::version` attribute or version value
 +  --> $DIR/check_clippy_version_attribute.rs:67:1
 +   |
 +LL | / declare_tool_lint! {
 +LL | |     pub clippy::MISSING_ATTRIBUTE_TWO,
 +LL | |     Warn,
 +LL | |     "Two",
 +LL | |     report_in_external_macro: true
 +LL | | }
 +   | |_^
 +   |
 +   = help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
 +   = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: aborting due to 4 previous errors
 +
index 242984680e163bd9eef1de3b132ffe93c7663c73,0000000000000000000000000000000000000000..32dd80246fab44cda2884f4a4f996d1e8f69d3e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- struct Foo {}
 +#![warn(clippy::struct_excessive_bools)]
 +
 +struct S {
 +    a: bool,
 +}
 +
++struct Foo;
 +
 +fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c40f77469b8207bcf2d8e4ae7e22751e3f9bbc8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,18 @@@
++// compile-flags: --emit=link
++// no-prefer-dynamic
++
++#![crate_type = "proc-macro"]
++
++extern crate proc_macro;
++
++use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree};
++
++#[proc_macro]
++pub fn unsafe_block(input: TokenStream) -> TokenStream {
++    let span = input.into_iter().next().unwrap().span();
++    TokenStream::from_iter([TokenTree::Ident(Ident::new("unsafe", span)), {
++        let mut group = Group::new(Delimiter::Brace, TokenStream::new());
++        group.set_span(span);
++        TokenTree::Group(group)
++    }])
++}
index 8a7afa934502d101c33d81e1e8d8f26ff435fa27,0000000000000000000000000000000000000000..9851d4791d8db59da4c1bcf333b770e7148f5119
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,22 @@@
- error: called `.byte().nth()` on a `String`
++error: called `.bytes().nth()` on a `String`
 +  --> $DIR/bytes_nth.rs:8:13
 +   |
 +LL |     let _ = s.bytes().nth(3);
 +   |             ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
 +   |
 +   = note: `-D clippy::bytes-nth` implied by `-D warnings`
 +
- error: called `.byte().nth()` on a `String`
++error: called `.bytes().nth()` on a `String`
 +  --> $DIR/bytes_nth.rs:9:14
 +   |
 +LL |     let _ = &s.bytes().nth(3);
 +   |              ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
 +
- error: called `.byte().nth()` on a `str`
++error: called `.bytes().nth()` on a `str`
 +  --> $DIR/bytes_nth.rs:10:13
 +   |
 +LL |     let _ = s[..].bytes().nth(3);
 +   |             ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)`
 +
 +error: aborting due to 3 previous errors
 +
index 68719c2bc6d05ea1afa005e00caee7f3c83b2418,0000000000000000000000000000000000000000..0d65071af15ed1c4694daec5b20dac9baa96e56a
mode 100644,000000..100644
--- /dev/null
@@@ -1,44 -1,0 +1,44 @@@
- struct TestStruct {}
 +#![warn(clippy::case_sensitive_file_extension_comparisons)]
 +
 +use std::string::String;
 +
++struct TestStruct;
 +
 +impl TestStruct {
 +    fn ends_with(self, arg: &str) {}
 +}
 +
 +fn is_rust_file(filename: &str) -> bool {
 +    filename.ends_with(".rs")
 +}
 +
 +fn main() {
 +    // std::string::String and &str should trigger the lint failure with .ext12
 +    let _ = String::from("").ends_with(".ext12");
 +    let _ = "str".ends_with(".ext12");
 +
 +    // The test struct should not trigger the lint failure with .ext12
 +    TestStruct {}.ends_with(".ext12");
 +
 +    // std::string::String and &str should trigger the lint failure with .EXT12
 +    let _ = String::from("").ends_with(".EXT12");
 +    let _ = "str".ends_with(".EXT12");
 +
 +    // The test struct should not trigger the lint failure with .EXT12
 +    TestStruct {}.ends_with(".EXT12");
 +
 +    // Should not trigger the lint failure with .eXT12
 +    let _ = String::from("").ends_with(".eXT12");
 +    let _ = "str".ends_with(".eXT12");
 +    TestStruct {}.ends_with(".eXT12");
 +
 +    // Should not trigger the lint failure with .EXT123 (too long)
 +    let _ = String::from("").ends_with(".EXT123");
 +    let _ = "str".ends_with(".EXT123");
 +    TestStruct {}.ends_with(".EXT123");
 +
 +    // Shouldn't fail if it doesn't start with a dot
 +    let _ = String::from("").ends_with("a.ext");
 +    let _ = "str".ends_with("a.extA");
 +    TestStruct {}.ends_with("a.ext");
 +}
index 2e31ad3172ee8cef1a5271c27c2fd8367b7d417c,0000000000000000000000000000000000000000..cf85a5ca931dd1e560134cf39304659254af3b43
mode 100644,000000..100644
--- /dev/null
@@@ -1,254 -1,0 +1,254 @@@
- #[allow(clippy::no_effect, clippy::unnecessary_operation)]
 +#![feature(repr128)]
 +#![allow(incomplete_features)]
 +
 +#[warn(
 +    clippy::cast_precision_loss,
 +    clippy::cast_possible_truncation,
 +    clippy::cast_sign_loss,
 +    clippy::cast_possible_wrap
 +)]
++#[allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
 +fn main() {
 +    // Test clippy::cast_precision_loss
 +    let x0 = 1i32;
 +    x0 as f32;
 +    let x1 = 1i64;
 +    x1 as f32;
 +    x1 as f64;
 +    let x2 = 1u32;
 +    x2 as f32;
 +    let x3 = 1u64;
 +    x3 as f32;
 +    x3 as f64;
 +    // Test clippy::cast_possible_truncation
 +    1f32 as i32;
 +    1f32 as u32;
 +    1f64 as f32;
 +    1i32 as i8;
 +    1i32 as u8;
 +    1f64 as isize;
 +    1f64 as usize;
 +    // Test clippy::cast_possible_wrap
 +    1u8 as i8;
 +    1u16 as i16;
 +    1u32 as i32;
 +    1u64 as i64;
 +    1usize as isize;
 +    // Test clippy::cast_sign_loss
 +    1i32 as u32;
 +    -1i32 as u32;
 +    1isize as usize;
 +    -1isize as usize;
 +    0i8 as u8;
 +    i8::MAX as u8;
 +    i16::MAX as u16;
 +    i32::MAX as u32;
 +    i64::MAX as u64;
 +    i128::MAX as u128;
 +
 +    (-1i8).abs() as u8;
 +    (-1i16).abs() as u16;
 +    (-1i32).abs() as u32;
 +    (-1i64).abs() as u64;
 +    (-1isize).abs() as usize;
 +
 +    (-1i8).checked_abs().unwrap() as u8;
 +    (-1i16).checked_abs().unwrap() as u16;
 +    (-1i32).checked_abs().unwrap() as u32;
 +    (-1i64).checked_abs().unwrap() as u64;
 +    (-1isize).checked_abs().unwrap() as usize;
 +
 +    (-1i8).rem_euclid(1i8) as u8;
 +    (-1i8).rem_euclid(1i8) as u16;
 +    (-1i16).rem_euclid(1i16) as u16;
 +    (-1i16).rem_euclid(1i16) as u32;
 +    (-1i32).rem_euclid(1i32) as u32;
 +    (-1i32).rem_euclid(1i32) as u64;
 +    (-1i64).rem_euclid(1i64) as u64;
 +    (-1i64).rem_euclid(1i64) as u128;
 +    (-1isize).rem_euclid(1isize) as usize;
 +    (1i8).rem_euclid(-1i8) as u8;
 +    (1i8).rem_euclid(-1i8) as u16;
 +    (1i16).rem_euclid(-1i16) as u16;
 +    (1i16).rem_euclid(-1i16) as u32;
 +    (1i32).rem_euclid(-1i32) as u32;
 +    (1i32).rem_euclid(-1i32) as u64;
 +    (1i64).rem_euclid(-1i64) as u64;
 +    (1i64).rem_euclid(-1i64) as u128;
 +    (1isize).rem_euclid(-1isize) as usize;
 +
 +    (-1i8).checked_rem_euclid(1i8).unwrap() as u8;
 +    (-1i8).checked_rem_euclid(1i8).unwrap() as u16;
 +    (-1i16).checked_rem_euclid(1i16).unwrap() as u16;
 +    (-1i16).checked_rem_euclid(1i16).unwrap() as u32;
 +    (-1i32).checked_rem_euclid(1i32).unwrap() as u32;
 +    (-1i32).checked_rem_euclid(1i32).unwrap() as u64;
 +    (-1i64).checked_rem_euclid(1i64).unwrap() as u64;
 +    (-1i64).checked_rem_euclid(1i64).unwrap() as u128;
 +    (-1isize).checked_rem_euclid(1isize).unwrap() as usize;
 +    (1i8).checked_rem_euclid(-1i8).unwrap() as u8;
 +    (1i8).checked_rem_euclid(-1i8).unwrap() as u16;
 +    (1i16).checked_rem_euclid(-1i16).unwrap() as u16;
 +    (1i16).checked_rem_euclid(-1i16).unwrap() as u32;
 +    (1i32).checked_rem_euclid(-1i32).unwrap() as u32;
 +    (1i32).checked_rem_euclid(-1i32).unwrap() as u64;
 +    (1i64).checked_rem_euclid(-1i64).unwrap() as u64;
 +    (1i64).checked_rem_euclid(-1i64).unwrap() as u128;
 +    (1isize).checked_rem_euclid(-1isize).unwrap() as usize;
 +
 +    // no lint for `cast_possible_truncation`
 +    // with `signum` method call (see issue #5395)
 +    let x: i64 = 5;
 +    let _ = x.signum() as i32;
 +
 +    let s = x.signum();
 +    let _ = s as i32;
 +
 +    // Test for signed min
 +    (-99999999999i64).min(1) as i8; // should be linted because signed
 +
 +    // Test for various operations that remove enough bits for the result to fit
 +    (999999u64 & 1) as u8;
 +    (999999u64 % 15) as u8;
 +    (999999u64 / 0x1_0000_0000_0000) as u16;
 +    ({ 999999u64 >> 56 }) as u8;
 +    ({
 +        let x = 999999u64;
 +        x.min(1)
 +    }) as u8;
 +    999999u64.clamp(0, 255) as u8;
 +    999999u64.clamp(0, 256) as u8; // should still be linted
 +
 +    #[derive(Clone, Copy)]
 +    enum E1 {
 +        A,
 +        B,
 +        C,
 +    }
 +    impl E1 {
 +        fn test(self) {
 +            let _ = self as u8; // Don't lint. `0..=2` fits in u8
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    enum E2 {
 +        A = 255,
 +        B,
 +    }
 +    impl E2 {
 +        fn test(self) {
 +            let _ = self as u8;
 +            let _ = Self::B as u8;
 +            let _ = self as i16; // Don't lint. `255..=256` fits in i16
 +            let _ = Self::A as u8; // Don't lint.
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    enum E3 {
 +        A = -1,
 +        B,
 +        C = 50,
 +    }
 +    impl E3 {
 +        fn test(self) {
 +            let _ = self as i8; // Don't lint. `-1..=50` fits in i8
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    enum E4 {
 +        A = -128,
 +        B,
 +    }
 +    impl E4 {
 +        fn test(self) {
 +            let _ = self as i8; // Don't lint. `-128..=-127` fits in i8
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    enum E5 {
 +        A = -129,
 +        B = 127,
 +    }
 +    impl E5 {
 +        fn test(self) {
 +            let _ = self as i8;
 +            let _ = Self::A as i8;
 +            let _ = self as i16; // Don't lint. `-129..=127` fits in i16
 +            let _ = Self::B as u8; // Don't lint.
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    #[repr(u32)]
 +    enum E6 {
 +        A = u16::MAX as u32,
 +        B,
 +    }
 +    impl E6 {
 +        fn test(self) {
 +            let _ = self as i16;
 +            let _ = Self::A as u16; // Don't lint. `2^16-1` fits in u16
 +            let _ = self as u32; // Don't lint. `2^16-1..=2^16` fits in u32
 +            let _ = Self::A as u16; // Don't lint.
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    #[repr(u64)]
 +    enum E7 {
 +        A = u32::MAX as u64,
 +        B,
 +    }
 +    impl E7 {
 +        fn test(self) {
 +            let _ = self as usize;
 +            let _ = Self::A as usize; // Don't lint.
 +            let _ = self as u64; // Don't lint. `2^32-1..=2^32` fits in u64
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    #[repr(i128)]
 +    enum E8 {
 +        A = i128::MIN,
 +        B,
 +        C = 0,
 +        D = i128::MAX,
 +    }
 +    impl E8 {
 +        fn test(self) {
 +            let _ = self as i128; // Don't lint. `-(2^127)..=2^127-1` fits it i128
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    #[repr(u128)]
 +    enum E9 {
 +        A,
 +        B = u128::MAX,
 +    }
 +    impl E9 {
 +        fn test(self) {
 +            let _ = Self::A as u8; // Don't lint.
 +            let _ = self as u128; // Don't lint. `0..=2^128-1` fits in u128
 +        }
 +    }
 +
 +    #[derive(Clone, Copy)]
 +    #[repr(usize)]
 +    enum E10 {
 +        A,
 +        B = u32::MAX as usize,
 +    }
 +    impl E10 {
 +        fn test(self) {
 +            let _ = self as u16;
 +            let _ = Self::B as u32; // Don't lint.
 +            let _ = self as u64; // Don't lint.
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4ec2465be06db74a6ac1d4e70585aa4020ba33bc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++// run-rustfix
++#![warn(clippy::cast_abs_to_unsigned)]
++
++fn main() {
++    let x: i32 = -42;
++    let y: u32 = x.unsigned_abs();
++    println!("The absolute value of {} is {}", x, y);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..59b9c8c367883b7883f05a8d065d9e688ee68eca
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++// run-rustfix
++#![warn(clippy::cast_abs_to_unsigned)]
++
++fn main() {
++    let x: i32 = -42;
++    let y: u32 = x.abs() as u32;
++    println!("The absolute value of {} is {}", x, y);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..eb12857357a444abaf62ec93b3350e9c67565f62
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++error: casting the result of `i32::abs()` to u32
++  --> $DIR/cast_abs_to_unsigned.rs:6:18
++   |
++LL |     let y: u32 = x.abs() as u32;
++   |                  ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
++   |
++   = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
++
++error: aborting due to previous error
++
index 659591fffbecdb56993cdf8cbd8676430ec52e8c,0000000000000000000000000000000000000000..e4e7290a30e9e711c911c34d96a1239af8e0d19a
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,51 @@@
 +//! Test casts for alignment issues
 +
 +#![feature(rustc_private)]
++#![feature(core_intrinsics)]
 +extern crate libc;
 +
 +#[warn(clippy::cast_ptr_alignment)]
 +#[allow(
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::cast_lossless,
 +    clippy::borrow_as_ptr
 +)]
 +
 +fn main() {
 +    /* These should be warned against */
 +
 +    // cast to more-strictly-aligned type
 +    (&1u8 as *const u8) as *const u16;
 +    (&mut 1u8 as *mut u8) as *mut u16;
 +
 +    // cast to more-strictly-aligned type, but with the `pointer::cast` function.
 +    (&1u8 as *const u8).cast::<u16>();
 +    (&mut 1u8 as *mut u8).cast::<u16>();
 +
 +    /* These should be ok */
 +
 +    // not a pointer type
 +    1u8 as u16;
 +    // cast to less-strictly-aligned type
 +    (&1u16 as *const u16) as *const u8;
 +    (&mut 1u16 as *mut u16) as *mut u8;
 +    // For c_void, we should trust the user. See #2677
 +    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
 +    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
 +    // For ZST, we should trust the user. See #4256
 +    (&1u32 as *const u32 as *const ()) as *const u32;
++
++    // Issue #2881
++    let mut data = [0u8, 0u8];
++    unsafe {
++        let ptr = &data as *const [u8; 2] as *const u8;
++        let _ = (ptr as *const u16).read_unaligned();
++        let _ = core::ptr::read_unaligned(ptr as *const u16);
++        let _ = core::intrinsics::unaligned_volatile_load(ptr as *const u16);
++        let ptr = &mut data as *mut [u8; 2] as *mut u8;
++        let _ = (ptr as *mut u16).write_unaligned(0);
++        let _ = core::ptr::write_unaligned(ptr as *mut u16, 0);
++        let _ = core::intrinsics::unaligned_volatile_store(ptr as *mut u16, 0);
++    }
 +}
index aedd368445554b05ad2d1744be82e682081534d4,0000000000000000000000000000000000000000..5df2b5b1094be2b96bd552184326695820fb6b6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
-   --> $DIR/cast_alignment.rs:18:5
 +error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
-   --> $DIR/cast_alignment.rs:19:5
++  --> $DIR/cast_alignment.rs:19:5
 +   |
 +LL |     (&1u8 as *const u8) as *const u16;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings`
 +
 +error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
-   --> $DIR/cast_alignment.rs:22:5
++  --> $DIR/cast_alignment.rs:20:5
 +   |
 +LL |     (&mut 1u8 as *mut u8) as *mut u16;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
-   --> $DIR/cast_alignment.rs:23:5
++  --> $DIR/cast_alignment.rs:23:5
 +   |
 +LL |     (&1u8 as *const u8).cast::<u16>();
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
++  --> $DIR/cast_alignment.rs:24:5
 +   |
 +LL |     (&mut 1u8 as *mut u8).cast::<u16>();
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 4 previous errors
 +
index d44b0fae82001b3824b2a83c8d44e74eddacb0d8,0000000000000000000000000000000000000000..88cfa1f923c0bff23329871fa193c2698e3c65b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,27 @@@
- pub struct Foo {}
 +use std::collections::HashSet;
 +
 +// See rust-lang/rust-clippy#2774.
 +
 +#[derive(Eq, PartialEq, Debug, Hash)]
 +pub struct Bar {
 +    foo: Foo,
 +}
 +
 +#[derive(Eq, PartialEq, Debug, Hash)]
++pub struct Foo;
 +
 +#[allow(clippy::implicit_hasher)]
 +// This should not cause a "cannot relate bound region" ICE.
 +pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
 +    let mut foos = HashSet::new();
 +    foos.extend(bars.iter().map(|b| &b.foo));
 +}
 +
 +#[allow(clippy::implicit_hasher)]
 +// Also, this should not cause a "cannot relate bound region" ICE.
 +pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) {
 +    let mut foos = HashSet::new();
 +    foos.extend(bars.iter().map(|b| &b.foo));
 +}
 +
 +fn main() {}
index 8d9a1af8ff1180b50e824588b55bbcddc0cb93ea,0000000000000000000000000000000000000000..4fe92d356c44de5f2d2f24f2292d6135b8b4aa9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,21 @@@
- struct Foo {}
 +//! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179.
 +//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details.
 +
 +#![warn(clippy::use_self)]
 +#![allow(dead_code)]
 +
++struct Foo;
 +
 +impl Foo {
 +    fn new() -> Self {
 +        impl Foo {
 +            fn bar() {}
 +        }
 +
 +        let _: _ = 1;
 +
 +        Self {}
 +    }
 +}
 +
 +fn main() {}
index 0e2ab1a39b82f98c0faefe4187c36f3c52b5a78f,0000000000000000000000000000000000000000..9cbafc716b5000dc2bd4ac51904fa90369df037a
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,20 @@@
- struct Foo {}
 +//! This is a reproducer for the ICE 6792: https://github.com/rust-lang/rust-clippy/issues/6792.
 +//! The ICE is caused by using `TyCtxt::type_of(assoc_type_id)`.
 +
 +trait Trait {
 +    type Ty;
 +
 +    fn broken() -> Self::Ty;
 +}
 +
++struct Foo;
 +
 +impl Trait for Foo {
 +    type Ty = Foo;
 +
 +    fn broken() -> Self::Ty {
 +        Self::Ty {}
 +    }
 +}
 +
 +fn main() {}
index 111350a6280dc44a4415e30f74fe636f673c0f0e,0000000000000000000000000000000000000000..1a33e647588f19ea3c6c678285c23ae9e483b57c
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,11 @@@
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL ~     unsafe { 0 };
-    |
 +error: unsafe block missing a safety comment
 +  --> $DIR/auxiliary/ice-7868-aux.rs:2:5
 +   |
 +LL |     unsafe { 0 };
 +   |     ^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
++   = help: consider adding a safety comment on the preceding line
 +
 +error: aborting due to previous error
 +
index 676564b2445d506185bb5d9bafe68c15ab3538a9,0000000000000000000000000000000000000000..376ff97ba6036f3fbbf6336504a73610b910dc4f
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,20 @@@
- struct Bar {}
 +#![deny(clippy::needless_lifetimes)]
 +#![allow(dead_code)]
 +
 +trait Foo {}
 +
++struct Bar;
 +
 +struct Baz<'a> {
 +    bar: &'a Bar,
 +}
 +
 +impl<'a> Foo for Baz<'a> {}
 +
 +impl Bar {
 +    fn baz<'a>(&'a self) -> impl Foo + 'a {
 +        Baz { bar: self }
 +    }
 +}
 +
 +fn main() {}
index a41bcb33b4460bf386f714057c377e50ea54ba14,0000000000000000000000000000000000000000..6f9d98bbfe7f341b8b166800314b77495ba0697a
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
- struct A {}
 +#![allow(clippy::blacklisted_name)]
 +
 +pub fn foo(bar: *const u8) {
 +    println!("{:#p}", bar);
 +}
 +
 +// Regression test for https://github.com/rust-lang/rust-clippy/issues/4917
 +/// <foo
++struct A;
 +
 +fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9fc594be311e2fd23fe01dfc552b2ff703f1c483
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,56 @@@
++// run-rustfix
++#![warn(clippy::crate_in_macro_def)]
++
++mod hygienic {
++    #[macro_export]
++    macro_rules! print_message_hygienic {
++        () => {
++            println!("{}", $crate::hygienic::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++mod unhygienic {
++    #[macro_export]
++    macro_rules! print_message_unhygienic {
++        () => {
++            println!("{}", $crate::unhygienic::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++mod unhygienic_intentionally {
++    // For cases where the use of `crate` is intentional, applying `allow` to the macro definition
++    // should suppress the lint.
++    #[allow(clippy::crate_in_macro_def)]
++    #[macro_export]
++    macro_rules! print_message_unhygienic_intentionally {
++        () => {
++            println!("{}", crate::CALLER_PROVIDED_MESSAGE);
++        };
++    }
++}
++
++#[macro_use]
++mod not_exported {
++    macro_rules! print_message_not_exported {
++        () => {
++            println!("{}", crate::not_exported::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++fn main() {
++    print_message_hygienic!();
++    print_message_unhygienic!();
++    print_message_unhygienic_intentionally!();
++    print_message_not_exported!();
++}
++
++pub const CALLER_PROVIDED_MESSAGE: &str = "Hello!";
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ac456108e4ab15fb842d210c5605dcb9d3342122
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,56 @@@
++// run-rustfix
++#![warn(clippy::crate_in_macro_def)]
++
++mod hygienic {
++    #[macro_export]
++    macro_rules! print_message_hygienic {
++        () => {
++            println!("{}", $crate::hygienic::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++mod unhygienic {
++    #[macro_export]
++    macro_rules! print_message_unhygienic {
++        () => {
++            println!("{}", crate::unhygienic::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++mod unhygienic_intentionally {
++    // For cases where the use of `crate` is intentional, applying `allow` to the macro definition
++    // should suppress the lint.
++    #[allow(clippy::crate_in_macro_def)]
++    #[macro_export]
++    macro_rules! print_message_unhygienic_intentionally {
++        () => {
++            println!("{}", crate::CALLER_PROVIDED_MESSAGE);
++        };
++    }
++}
++
++#[macro_use]
++mod not_exported {
++    macro_rules! print_message_not_exported {
++        () => {
++            println!("{}", crate::not_exported::MESSAGE);
++        };
++    }
++
++    pub const MESSAGE: &str = "Hello!";
++}
++
++fn main() {
++    print_message_hygienic!();
++    print_message_unhygienic!();
++    print_message_unhygienic_intentionally!();
++    print_message_not_exported!();
++}
++
++pub const CALLER_PROVIDED_MESSAGE: &str = "Hello!";
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9ac5937dcc0634da7cdbd4f1fa2db106e175391d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++error: `crate` references the macro call's crate
++  --> $DIR/crate_in_macro_def.rs:19:28
++   |
++LL |             println!("{}", crate::unhygienic::MESSAGE);
++   |                            ^^^^^ help: to reference the macro definition's crate, use: `$crate`
++   |
++   = note: `-D clippy::crate-in-macro-def` implied by `-D warnings`
++
++error: aborting due to previous error
++
index 1b0e7544e79c6289f17b6d48b9f1a0dc7c51e579,0000000000000000000000000000000000000000..e0b4a2f6942392c575e3f491914dfbf11b7cf6cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,174 @@@
-     struct StructForMethodCallTest {}
 +// run-rustfix
 +// aux-build:macro_rules.rs
 +
 +#![warn(clippy::default_numeric_fallback)]
 +#![allow(unused)]
 +#![allow(clippy::never_loop)]
 +#![allow(clippy::no_effect)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::branches_sharing_code)]
 +#![allow(clippy::match_single_binding)]
 +
 +#[macro_use]
 +extern crate macro_rules;
 +
 +mod basic_expr {
 +    fn test() {
 +        // Should lint unsuffixed literals typed `f64`.
 +        let x = 0.12_f64;
 +        let x = [1.0_f64, 2.0_f64, 3.0_f64];
 +        let x = if true { (1.0_f64, 2.0_f64) } else { (3.0_f64, 4.0_f64) };
 +        let x = match 1.0_f64 {
 +            _ => 1.0_f64,
 +        };
 +
 +        // Should NOT lint suffixed literals.
 +        let x = 0.12_f64;
 +
 +        // Should NOT lint literals in init expr if `Local` has a type annotation.
 +        let x: f64 = 0.1;
 +        let x: [f64; 3] = [1., 2., 3.];
 +        let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
 +        let x: _ = 1.;
 +    }
 +}
 +
 +mod nested_local {
 +    fn test() {
 +        let x: _ = {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.0_f64;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1.
 +        };
 +
 +        let x: _ = if true {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.0_f64;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1.
 +        } else {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.0_f64;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            2.
 +        };
 +    }
 +}
 +
 +mod function_def {
 +    fn ret_f64() -> f64 {
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        1.0_f64
 +    }
 +
 +    fn test() {
 +        // Should lint this because return type is inferred to `f64` and NOT bound to a concrete
 +        // type.
 +        let f = || -> _ { 1.0_f64 };
 +
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        let f = || -> f64 { 1.0_f64 };
 +    }
 +}
 +
 +mod function_calls {
 +    fn concrete_arg(f: f64) {}
 +
 +    fn generic_arg<T>(t: T) {}
 +
 +    fn test() {
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        concrete_arg(1.);
 +
 +        // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type.
 +        generic_arg(1.0_f64);
 +
 +        // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type.
 +        let x: _ = generic_arg(1.0_f64);
 +    }
 +}
 +
 +mod struct_ctor {
 +    struct ConcreteStruct {
 +        x: f64,
 +    }
 +
 +    struct GenericStruct<T> {
 +        x: T,
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteStruct { x: 1. };
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        GenericStruct { x: 1.0_f64 };
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        let _ = GenericStruct { x: 1.0_f64 };
 +    }
 +}
 +
 +mod enum_ctor {
 +    enum ConcreteEnum {
 +        X(f64),
 +    }
 +
 +    enum GenericEnum<T> {
 +        X(T),
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteEnum::X(1.);
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        GenericEnum::X(1.0_f64);
 +    }
 +}
 +
 +mod method_calls {
++    struct StructForMethodCallTest;
 +
 +    impl StructForMethodCallTest {
 +        fn concrete_arg(&self, f: f64) {}
 +
 +        fn generic_arg<T>(&self, t: T) {}
 +    }
 +
 +    fn test() {
 +        let s = StructForMethodCallTest {};
 +
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        s.concrete_arg(1.);
 +
 +        // Should lint this because the argument type is bound to a concrete type.
 +        s.generic_arg(1.0_f64);
 +    }
 +}
 +
 +mod in_macro {
 +    macro_rules! internal_macro {
 +        () => {
 +            let x = 22.0_f64;
 +        };
 +    }
 +
 +    // Should lint in internal macro.
 +    fn internal() {
 +        internal_macro!();
 +    }
 +
 +    // Should NOT lint in external macro.
 +    fn external() {
 +        default_numeric_fallback!();
 +    }
 +}
 +
 +fn main() {}
index e9687777bbd0bed95d74767187deb9566e5e8167,0000000000000000000000000000000000000000..50bbb6eec6c700fdbdb7a54051e48c21715b0dbd
mode 100644,000000..100644
--- /dev/null
@@@ -1,174 -1,0 +1,174 @@@
-     struct StructForMethodCallTest {}
 +// run-rustfix
 +// aux-build:macro_rules.rs
 +
 +#![warn(clippy::default_numeric_fallback)]
 +#![allow(unused)]
 +#![allow(clippy::never_loop)]
 +#![allow(clippy::no_effect)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::branches_sharing_code)]
 +#![allow(clippy::match_single_binding)]
 +
 +#[macro_use]
 +extern crate macro_rules;
 +
 +mod basic_expr {
 +    fn test() {
 +        // Should lint unsuffixed literals typed `f64`.
 +        let x = 0.12;
 +        let x = [1., 2., 3.];
 +        let x = if true { (1., 2.) } else { (3., 4.) };
 +        let x = match 1. {
 +            _ => 1.,
 +        };
 +
 +        // Should NOT lint suffixed literals.
 +        let x = 0.12_f64;
 +
 +        // Should NOT lint literals in init expr if `Local` has a type annotation.
 +        let x: f64 = 0.1;
 +        let x: [f64; 3] = [1., 2., 3.];
 +        let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
 +        let x: _ = 1.;
 +    }
 +}
 +
 +mod nested_local {
 +    fn test() {
 +        let x: _ = {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1.
 +        };
 +
 +        let x: _ = if true {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1.
 +        } else {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1.;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            2.
 +        };
 +    }
 +}
 +
 +mod function_def {
 +    fn ret_f64() -> f64 {
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        1.
 +    }
 +
 +    fn test() {
 +        // Should lint this because return type is inferred to `f64` and NOT bound to a concrete
 +        // type.
 +        let f = || -> _ { 1. };
 +
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        let f = || -> f64 { 1. };
 +    }
 +}
 +
 +mod function_calls {
 +    fn concrete_arg(f: f64) {}
 +
 +    fn generic_arg<T>(t: T) {}
 +
 +    fn test() {
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        concrete_arg(1.);
 +
 +        // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type.
 +        generic_arg(1.);
 +
 +        // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type.
 +        let x: _ = generic_arg(1.);
 +    }
 +}
 +
 +mod struct_ctor {
 +    struct ConcreteStruct {
 +        x: f64,
 +    }
 +
 +    struct GenericStruct<T> {
 +        x: T,
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteStruct { x: 1. };
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        GenericStruct { x: 1. };
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        let _ = GenericStruct { x: 1. };
 +    }
 +}
 +
 +mod enum_ctor {
 +    enum ConcreteEnum {
 +        X(f64),
 +    }
 +
 +    enum GenericEnum<T> {
 +        X(T),
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteEnum::X(1.);
 +
 +        // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type.
 +        GenericEnum::X(1.);
 +    }
 +}
 +
 +mod method_calls {
++    struct StructForMethodCallTest;
 +
 +    impl StructForMethodCallTest {
 +        fn concrete_arg(&self, f: f64) {}
 +
 +        fn generic_arg<T>(&self, t: T) {}
 +    }
 +
 +    fn test() {
 +        let s = StructForMethodCallTest {};
 +
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        s.concrete_arg(1.);
 +
 +        // Should lint this because the argument type is bound to a concrete type.
 +        s.generic_arg(1.);
 +    }
 +}
 +
 +mod in_macro {
 +    macro_rules! internal_macro {
 +        () => {
 +            let x = 22.;
 +        };
 +    }
 +
 +    // Should lint in internal macro.
 +    fn internal() {
 +        internal_macro!();
 +    }
 +
 +    // Should NOT lint in external macro.
 +    fn external() {
 +        default_numeric_fallback!();
 +    }
 +}
 +
 +fn main() {}
index 55c082fcb19fb7f1b563539721f9a89b111ba14b,0000000000000000000000000000000000000000..bded9e2c0e801723b89547d606120a989078473d
mode 100644,000000..100644
--- /dev/null
@@@ -1,173 -1,0 +1,173 @@@
-     struct StructForMethodCallTest {}
 +// run-rustfix
 +// aux-build:macro_rules.rs
 +
 +#![warn(clippy::default_numeric_fallback)]
 +#![allow(unused)]
 +#![allow(clippy::never_loop)]
 +#![allow(clippy::no_effect)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::branches_sharing_code)]
 +
 +#[macro_use]
 +extern crate macro_rules;
 +
 +mod basic_expr {
 +    fn test() {
 +        // Should lint unsuffixed literals typed `i32`.
 +        let x = 22_i32;
 +        let x = [1_i32, 2_i32, 3_i32];
 +        let x = if true { (1_i32, 2_i32) } else { (3_i32, 4_i32) };
 +        let x = match 1_i32 {
 +            1_i32 => 1_i32,
 +            _ => 2_i32,
 +        };
 +
 +        // Should NOT lint suffixed literals.
 +        let x = 22_i32;
 +
 +        // Should NOT lint literals in init expr if `Local` has a type annotation.
 +        let x: [i32; 3] = [1, 2, 3];
 +        let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
 +        let x: _ = 1;
 +    }
 +}
 +
 +mod nested_local {
 +    fn test() {
 +        let x: _ = {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1_i32;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1
 +        };
 +
 +        let x: _ = if true {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1_i32;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1
 +        } else {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1_i32;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            2
 +        };
 +    }
 +}
 +
 +mod function_def {
 +    fn ret_i32() -> i32 {
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        1_i32
 +    }
 +
 +    fn test() {
 +        // Should lint this because return type is inferred to `i32` and NOT bound to a concrete
 +        // type.
 +        let f = || -> _ { 1_i32 };
 +
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        let f = || -> i32 { 1_i32 };
 +    }
 +}
 +
 +mod function_calls {
 +    fn concrete_arg(x: i32) {}
 +
 +    fn generic_arg<T>(t: T) {}
 +
 +    fn test() {
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        concrete_arg(1);
 +
 +        // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
 +        generic_arg(1_i32);
 +
 +        // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
 +        let x: _ = generic_arg(1_i32);
 +    }
 +}
 +
 +mod struct_ctor {
 +    struct ConcreteStruct {
 +        x: i32,
 +    }
 +
 +    struct GenericStruct<T> {
 +        x: T,
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteStruct { x: 1 };
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        GenericStruct { x: 1_i32 };
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        let _ = GenericStruct { x: 1_i32 };
 +    }
 +}
 +
 +mod enum_ctor {
 +    enum ConcreteEnum {
 +        X(i32),
 +    }
 +
 +    enum GenericEnum<T> {
 +        X(T),
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteEnum::X(1);
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        GenericEnum::X(1_i32);
 +    }
 +}
 +
 +mod method_calls {
++    struct StructForMethodCallTest;
 +
 +    impl StructForMethodCallTest {
 +        fn concrete_arg(&self, x: i32) {}
 +
 +        fn generic_arg<T>(&self, t: T) {}
 +    }
 +
 +    fn test() {
 +        let s = StructForMethodCallTest {};
 +
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        s.concrete_arg(1);
 +
 +        // Should lint this because the argument type is bound to a concrete type.
 +        s.generic_arg(1_i32);
 +    }
 +}
 +
 +mod in_macro {
 +    macro_rules! internal_macro {
 +        () => {
 +            let x = 22_i32;
 +        };
 +    }
 +
 +    // Should lint in internal macro.
 +    fn internal() {
 +        internal_macro!();
 +    }
 +
 +    // Should NOT lint in external macro.
 +    fn external() {
 +        default_numeric_fallback!();
 +    }
 +}
 +
 +fn main() {}
index e0a4828ce9ff636aed3c8c510e6e094b9f370826,0000000000000000000000000000000000000000..3fceefa551c7843c4d1b54a36f98c3ac86bf2612
mode 100644,000000..100644
--- /dev/null
@@@ -1,173 -1,0 +1,173 @@@
-     struct StructForMethodCallTest {}
 +// run-rustfix
 +// aux-build:macro_rules.rs
 +
 +#![warn(clippy::default_numeric_fallback)]
 +#![allow(unused)]
 +#![allow(clippy::never_loop)]
 +#![allow(clippy::no_effect)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::branches_sharing_code)]
 +
 +#[macro_use]
 +extern crate macro_rules;
 +
 +mod basic_expr {
 +    fn test() {
 +        // Should lint unsuffixed literals typed `i32`.
 +        let x = 22;
 +        let x = [1, 2, 3];
 +        let x = if true { (1, 2) } else { (3, 4) };
 +        let x = match 1 {
 +            1 => 1,
 +            _ => 2,
 +        };
 +
 +        // Should NOT lint suffixed literals.
 +        let x = 22_i32;
 +
 +        // Should NOT lint literals in init expr if `Local` has a type annotation.
 +        let x: [i32; 3] = [1, 2, 3];
 +        let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
 +        let x: _ = 1;
 +    }
 +}
 +
 +mod nested_local {
 +    fn test() {
 +        let x: _ = {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1
 +        };
 +
 +        let x: _ = if true {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            1
 +        } else {
 +            // Should lint this because this literal is not bound to any types.
 +            let y = 1;
 +
 +            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
 +            2
 +        };
 +    }
 +}
 +
 +mod function_def {
 +    fn ret_i32() -> i32 {
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        1
 +    }
 +
 +    fn test() {
 +        // Should lint this because return type is inferred to `i32` and NOT bound to a concrete
 +        // type.
 +        let f = || -> _ { 1 };
 +
 +        // Even though the output type is specified,
 +        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
 +        let f = || -> i32 { 1 };
 +    }
 +}
 +
 +mod function_calls {
 +    fn concrete_arg(x: i32) {}
 +
 +    fn generic_arg<T>(t: T) {}
 +
 +    fn test() {
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        concrete_arg(1);
 +
 +        // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
 +        generic_arg(1);
 +
 +        // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
 +        let x: _ = generic_arg(1);
 +    }
 +}
 +
 +mod struct_ctor {
 +    struct ConcreteStruct {
 +        x: i32,
 +    }
 +
 +    struct GenericStruct<T> {
 +        x: T,
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteStruct { x: 1 };
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        GenericStruct { x: 1 };
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        let _ = GenericStruct { x: 1 };
 +    }
 +}
 +
 +mod enum_ctor {
 +    enum ConcreteEnum {
 +        X(i32),
 +    }
 +
 +    enum GenericEnum<T> {
 +        X(T),
 +    }
 +
 +    fn test() {
 +        // Should NOT lint this because the field type is bound to a concrete type.
 +        ConcreteEnum::X(1);
 +
 +        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
 +        GenericEnum::X(1);
 +    }
 +}
 +
 +mod method_calls {
++    struct StructForMethodCallTest;
 +
 +    impl StructForMethodCallTest {
 +        fn concrete_arg(&self, x: i32) {}
 +
 +        fn generic_arg<T>(&self, t: T) {}
 +    }
 +
 +    fn test() {
 +        let s = StructForMethodCallTest {};
 +
 +        // Should NOT lint this because the argument type is bound to a concrete type.
 +        s.concrete_arg(1);
 +
 +        // Should lint this because the argument type is bound to a concrete type.
 +        s.generic_arg(1);
 +    }
 +}
 +
 +mod in_macro {
 +    macro_rules! internal_macro {
 +        () => {
 +            let x = 22;
 +        };
 +    }
 +
 +    // Should lint in internal macro.
 +    fn internal() {
 +        internal_macro!();
 +    }
 +
 +    // Should NOT lint in external macro.
 +    fn external() {
 +        default_numeric_fallback!();
 +    }
 +}
 +
 +fn main() {}
index 9ddd6d64701a61dd615ec0b1d1f5d5451601617f,0000000000000000000000000000000000000000..7c7a9ecff67f5a56efb13c560ba21417a3cf32d9
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,66 @@@
- struct SomeStruct {}
 +#![warn(clippy::drop_copy, clippy::forget_copy)]
 +#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)]
 +
 +use std::mem::{drop, forget};
 +use std::vec::Vec;
 +
 +#[derive(Copy, Clone)]
++struct SomeStruct;
 +
 +struct AnotherStruct {
 +    x: u8,
 +    y: u8,
 +    z: Vec<u8>,
 +}
 +
 +impl Clone for AnotherStruct {
 +    fn clone(&self) -> AnotherStruct {
 +        AnotherStruct {
 +            x: self.x,
 +            y: self.y,
 +            z: self.z.clone(),
 +        }
 +    }
 +}
 +
 +fn main() {
 +    let s1 = SomeStruct {};
 +    let s2 = s1;
 +    let s3 = &s1;
 +    let mut s4 = s1;
 +    let ref s5 = s1;
 +
 +    drop(s1);
 +    drop(s2);
 +    drop(s3);
 +    drop(s4);
 +    drop(s5);
 +
 +    forget(s1);
 +    forget(s2);
 +    forget(s3);
 +    forget(s4);
 +    forget(s5);
 +
 +    let a1 = AnotherStruct {
 +        x: 255,
 +        y: 0,
 +        z: vec![1, 2, 3],
 +    };
 +    let a2 = &a1;
 +    let mut a3 = a1.clone();
 +    let ref a4 = a1;
 +    let a5 = a1.clone();
 +
 +    drop(a2);
 +    drop(a3);
 +    drop(a4);
 +    drop(a5);
 +
 +    forget(a2);
 +    let a3 = &a1;
 +    forget(a3);
 +    forget(a4);
 +    let a5 = a1.clone();
 +    forget(a5);
 +}
index 01de0be7caea96cb907223cb49ddce57233d6eef,0000000000000000000000000000000000000000..88228afae89c005d698051baecdd76ee87f17ace
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,76 @@@
- note: argument has type SomeStruct
 +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:33:5
 +   |
 +LL |     drop(s1);
 +   |     ^^^^^^^^
 +   |
 +   = note: `-D clippy::drop-copy` implied by `-D warnings`
- note: argument has type SomeStruct
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:33:10
 +   |
 +LL |     drop(s1);
 +   |          ^^
 +
 +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:34:5
 +   |
 +LL |     drop(s2);
 +   |     ^^^^^^^^
 +   |
- note: argument has type SomeStruct
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:34:10
 +   |
 +LL |     drop(s2);
 +   |          ^^
 +
 +error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:36:5
 +   |
 +LL |     drop(s4);
 +   |     ^^^^^^^^
 +   |
- note: argument has type SomeStruct
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:36:10
 +   |
 +LL |     drop(s4);
 +   |          ^^
 +
 +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:39:5
 +   |
 +LL |     forget(s1);
 +   |     ^^^^^^^^^^
 +   |
 +   = note: `-D clippy::forget-copy` implied by `-D warnings`
- note: argument has type SomeStruct
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:39:12
 +   |
 +LL |     forget(s1);
 +   |            ^^
 +
 +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:40:5
 +   |
 +LL |     forget(s2);
 +   |     ^^^^^^^^^^
 +   |
- note: argument has type SomeStruct
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:40:12
 +   |
 +LL |     forget(s2);
 +   |            ^^
 +
 +error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
 +  --> $DIR/drop_forget_copy.rs:42:5
 +   |
 +LL |     forget(s4);
 +   |     ^^^^^^^^^^
 +   |
++note: argument has type `SomeStruct`
 +  --> $DIR/drop_forget_copy.rs:42:12
 +   |
 +LL |     forget(s4);
 +   |            ^^
 +
 +error: aborting due to 6 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5a0ebde82c5d4eea033c467a2f13c2c32f67bf09
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,40 @@@
++#![warn(clippy::drop_non_drop)]
++
++use core::mem::drop;
++
++fn make_result<T>(t: T) -> Result<T, ()> {
++    Ok(t)
++}
++
++#[must_use]
++fn must_use<T>(t: T) -> T {
++    t
++}
++
++fn drop_generic<T>(t: T) {
++    // Don't lint
++    drop(t)
++}
++
++fn main() {
++    struct Foo;
++    // Lint
++    drop(Foo);
++    // Don't lint
++    drop(make_result(Foo));
++    // Don't lint
++    drop(must_use(Foo));
++
++    struct Bar;
++    impl Drop for Bar {
++        fn drop(&mut self) {}
++    }
++    // Don't lint
++    drop(Bar);
++
++    struct Baz<T>(T);
++    // Lint
++    drop(Baz(Foo));
++    // Don't lint
++    drop(Baz(Bar));
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f73068901c503ac2ff3eb1b685b3336247b1ddd9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends it's contained lifetimes
++  --> $DIR/drop_non_drop.rs:22:5
++   |
++LL |     drop(Foo);
++   |     ^^^^^^^^^
++   |
++   = note: `-D clippy::drop-non-drop` implied by `-D warnings`
++note: argument has type `main::Foo`
++  --> $DIR/drop_non_drop.rs:22:10
++   |
++LL |     drop(Foo);
++   |          ^^^
++
++error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends it's contained lifetimes
++  --> $DIR/drop_non_drop.rs:37:5
++   |
++LL |     drop(Baz(Foo));
++   |     ^^^^^^^^^^^^^^
++   |
++note: argument has type `main::Baz<main::Foo>`
++  --> $DIR/drop_non_drop.rs:37:10
++   |
++LL |     drop(Baz(Foo));
++   |          ^^^^^^^^
++
++error: aborting due to 2 previous errors
++
index e1a15c609fd233d6adf784fb5294c7a3b191baed,0000000000000000000000000000000000000000..7de0b0bbdf9ae8ffdfb4019d695e4a38df8ad197
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,74 @@@
- #![allow(clippy::unnecessary_wraps)]
 +#![warn(clippy::drop_ref)]
 +#![allow(clippy::toplevel_ref_arg)]
 +#![allow(clippy::map_err_ignore)]
++#![allow(clippy::unnecessary_wraps, clippy::drop_non_drop)]
 +
 +use std::mem::drop;
 +
 +struct SomeStruct;
 +
 +fn main() {
 +    drop(&SomeStruct);
 +
 +    let mut owned1 = SomeStruct;
 +    drop(&owned1);
 +    drop(&&owned1);
 +    drop(&mut owned1);
 +    drop(owned1); //OK
 +
 +    let reference1 = &SomeStruct;
 +    drop(reference1);
 +
 +    let reference2 = &mut SomeStruct;
 +    drop(reference2);
 +
 +    let ref reference3 = SomeStruct;
 +    drop(reference3);
 +}
 +
 +#[allow(dead_code)]
 +fn test_generic_fn_drop<T>(val: T) {
 +    drop(&val);
 +    drop(val); //OK
 +}
 +
 +#[allow(dead_code)]
 +fn test_similarly_named_function() {
 +    fn drop<T>(_val: T) {}
 +    drop(&SomeStruct); //OK; call to unrelated function which happens to have the same name
 +    std::mem::drop(&SomeStruct);
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct Error;
 +fn produce_half_owl_error() -> Result<(), Error> {
 +    Ok(())
 +}
 +
 +fn produce_half_owl_ok() -> Result<bool, ()> {
 +    Ok(true)
 +}
 +
 +#[allow(dead_code)]
 +fn test_owl_result() -> Result<(), ()> {
 +    produce_half_owl_error().map_err(|_| ())?;
 +    produce_half_owl_ok().map(|_| ())?;
 +    // the following should not be linted,
 +    // we should not force users to use toilet closures
 +    // to produce owl results when drop is more convenient
 +    produce_half_owl_error().map_err(drop)?;
 +    produce_half_owl_ok().map_err(drop)?;
 +    Ok(())
 +}
 +
 +#[allow(dead_code)]
 +fn test_owl_result_2() -> Result<u8, ()> {
 +    produce_half_owl_error().map_err(|_| ())?;
 +    produce_half_owl_ok().map(|_| ())?;
 +    // the following should not be linted,
 +    // we should not force users to use toilet closures
 +    // to produce owl results when drop is more convenient
 +    produce_half_owl_error().map_err(drop)?;
 +    produce_half_owl_ok().map(drop)?;
 +    Ok(1)
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..80f07603b8d4f93ecf477ef4e2fd5cdeb7d3140f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++// run-rustfix
++#![warn(clippy::empty_structs_with_brackets)]
++#![allow(dead_code)]
++
++pub struct MyEmptyStruct; // should trigger lint
++struct MyEmptyTupleStruct; // should trigger lint
++
++// should not trigger lint
++struct MyCfgStruct {
++    #[cfg(feature = "thisisneverenabled")]
++    field: u8,
++}
++
++// should not trigger lint
++struct MyCfgTupleStruct(#[cfg(feature = "thisisneverenabled")] u8);
++
++// should not trigger lint
++struct MyStruct {
++    field: u8,
++}
++struct MyTupleStruct(usize, String); // should not trigger lint
++struct MySingleTupleStruct(usize); // should not trigger lint
++struct MyUnitLikeStruct; // should not trigger lint
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1d1ed4c769025526e118d89f1bea0581a66ab4a7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,25 @@@
++// run-rustfix
++#![warn(clippy::empty_structs_with_brackets)]
++#![allow(dead_code)]
++
++pub struct MyEmptyStruct {} // should trigger lint
++struct MyEmptyTupleStruct(); // should trigger lint
++
++// should not trigger lint
++struct MyCfgStruct {
++    #[cfg(feature = "thisisneverenabled")]
++    field: u8,
++}
++
++// should not trigger lint
++struct MyCfgTupleStruct(#[cfg(feature = "thisisneverenabled")] u8);
++
++// should not trigger lint
++struct MyStruct {
++    field: u8,
++}
++struct MyTupleStruct(usize, String); // should not trigger lint
++struct MySingleTupleStruct(usize); // should not trigger lint
++struct MyUnitLikeStruct; // should not trigger lint
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0308cb5571af25cf8442d14c67d64be91cc95347
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++error: found empty brackets on struct declaration
++  --> $DIR/empty_structs_with_brackets.rs:5:25
++   |
++LL | pub struct MyEmptyStruct {} // should trigger lint
++   |                         ^^^
++   |
++   = note: `-D clippy::empty-structs-with-brackets` implied by `-D warnings`
++   = help: remove the brackets
++
++error: found empty brackets on struct declaration
++  --> $DIR/empty_structs_with_brackets.rs:6:26
++   |
++LL | struct MyEmptyTupleStruct(); // should trigger lint
++   |                          ^^^
++   |
++   = help: remove the brackets
++
++error: aborting due to 2 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7e18d70bae4007313c76d384005d255fd921a2d9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++// run-rustfix
++
++struct MyTypeNonDebug;
++
++#[derive(Debug)]
++struct MyTypeDebug;
++
++fn main() {
++    let test_debug: Result<MyTypeDebug, u32> = Ok(MyTypeDebug);
++    test_debug.expect_err("Testing debug type");
++
++    let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
++    test_non_debug.err().expect("Testing non debug type");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bf8c3c9fb8c98f680adfaeb6a9e9f2fa30fc437a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,14 @@@
++// run-rustfix
++
++struct MyTypeNonDebug;
++
++#[derive(Debug)]
++struct MyTypeDebug;
++
++fn main() {
++    let test_debug: Result<MyTypeDebug, u32> = Ok(MyTypeDebug);
++    test_debug.err().expect("Testing debug type");
++
++    let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
++    test_non_debug.err().expect("Testing non debug type");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ffd97e00a5c09fa21dc16efa4ce028df4704e521
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++error: called `.err().expect()` on a `Result` value
++  --> $DIR/err_expect.rs:10:16
++   |
++LL |     test_debug.err().expect("Testing debug type");
++   |                ^^^^^^^^^^^^ help: try: `expect_err`
++   |
++   = note: `-D clippy::err-expect` implied by `-D warnings`
++
++error: aborting due to previous error
++
index 1442ee08e7546aa20056ccb5b3f27e894b6c4cb8,0000000000000000000000000000000000000000..f805bcc9ba8af503140bf2cff10433824147971b
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,45 @@@
- struct S {}
 +#![warn(clippy::fn_params_excessive_bools)]
 +#![allow(clippy::too_many_arguments)]
 +
 +extern "C" {
 +    fn f(_: bool, _: bool, _: bool, _: bool);
 +}
 +
 +macro_rules! foo {
 +    () => {
 +        fn fff(_: bool, _: bool, _: bool, _: bool) {}
 +    };
 +}
 +
 +foo!();
 +
 +#[no_mangle]
 +extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {}
 +fn g(_: bool, _: bool, _: bool, _: bool) {}
 +fn h(_: bool, _: bool, _: bool) {}
 +fn e(_: S, _: S, _: Box<S>, _: Vec<u32>) {}
 +fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
 +
++struct S;
 +trait Trait {
 +    fn f(_: bool, _: bool, _: bool, _: bool);
 +    fn g(_: bool, _: bool, _: bool, _: Vec<u32>);
 +}
 +
 +impl S {
 +    fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
 +    fn g(&self, _: bool, _: bool, _: bool) {}
 +    #[no_mangle]
 +    extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {}
 +}
 +
 +impl Trait for S {
 +    fn f(_: bool, _: bool, _: bool, _: bool) {}
 +    fn g(_: bool, _: bool, _: bool, _: Vec<u32>) {}
 +}
 +
 +fn main() {
 +    fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
 +        fn nn(_: bool, _: bool, _: bool, _: bool) {}
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7580cf95ebfa8214facad9f9338c14aa54dc7c68
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++#![warn(clippy::forget_non_drop)]
++
++use core::mem::forget;
++
++fn forget_generic<T>(t: T) {
++    // Don't lint
++    forget(t)
++}
++
++fn main() {
++    struct Foo;
++    // Lint
++    forget(Foo);
++
++    struct Bar;
++    impl Drop for Bar {
++        fn drop(&mut self) {}
++    }
++    // Don't lint
++    forget(Bar);
++
++    struct Baz<T>(T);
++    // Lint
++    forget(Baz(Foo));
++    // Don't lint
++    forget(Baz(Bar));
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..03fb00960a44732faaf1f9078952fe86884d77db
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++error: call to `std::mem::forget` with a value that does not implement `Drop`. Forgetting such a type is the same as dropping it
++  --> $DIR/forget_non_drop.rs:13:5
++   |
++LL |     forget(Foo);
++   |     ^^^^^^^^^^^
++   |
++   = note: `-D clippy::forget-non-drop` implied by `-D warnings`
++note: argument has type `main::Foo`
++  --> $DIR/forget_non_drop.rs:13:12
++   |
++LL |     forget(Foo);
++   |            ^^^
++
++error: call to `std::mem::forget` with a value that does not implement `Drop`. Forgetting such a type is the same as dropping it
++  --> $DIR/forget_non_drop.rs:24:5
++   |
++LL |     forget(Baz(Foo));
++   |     ^^^^^^^^^^^^^^^^
++   |
++note: argument has type `main::Baz<main::Foo>`
++  --> $DIR/forget_non_drop.rs:24:12
++   |
++LL |     forget(Baz(Foo));
++   |            ^^^^^^^^
++
++error: aborting due to 2 previous errors
++
index c49e6756a6c5bed9db7e73e40ae7acbf5aebb260,0000000000000000000000000000000000000000..6c8c4c9c0edecc01adeaee75a87681af5b94dc06
mode 100644,000000..100644
--- /dev/null
@@@ -1,49 -1,0 +1,49 @@@
- #![allow(clippy::unnecessary_wraps)]
 +#![warn(clippy::forget_ref)]
 +#![allow(clippy::toplevel_ref_arg)]
++#![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)]
 +
 +use std::mem::forget;
 +
 +struct SomeStruct;
 +
 +fn main() {
 +    forget(&SomeStruct);
 +
 +    let mut owned = SomeStruct;
 +    forget(&owned);
 +    forget(&&owned);
 +    forget(&mut owned);
 +    forget(owned); //OK
 +
 +    let reference1 = &SomeStruct;
 +    forget(&*reference1);
 +
 +    let reference2 = &mut SomeStruct;
 +    forget(reference2);
 +
 +    let ref reference3 = SomeStruct;
 +    forget(reference3);
 +}
 +
 +#[allow(dead_code)]
 +fn test_generic_fn_forget<T>(val: T) {
 +    forget(&val);
 +    forget(val); //OK
 +}
 +
 +#[allow(dead_code)]
 +fn test_similarly_named_function() {
 +    fn forget<T>(_val: T) {}
 +    forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name
 +    std::mem::forget(&SomeStruct);
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct Error;
 +fn produce_half_owl_error() -> Result<(), Error> {
 +    Ok(())
 +}
 +
 +fn produce_half_owl_ok() -> Result<bool, ()> {
 +    Ok(true)
 +}
index 12bbda71f434813ca78c1e499bb3d70e82106490,0000000000000000000000000000000000000000..edc3fe1aec13a556fa0c8c2121a1639553c57952
mode 100644,000000..100644
--- /dev/null
@@@ -1,69 -1,0 +1,78 @@@
 +const ONE: i64 = 1;
 +const NEG_ONE: i64 = -1;
 +const ZERO: i64 = 0;
 +
 +struct A(String);
 +
 +impl std::ops::Shl<i32> for A {
 +    type Output = A;
 +    fn shl(mut self, other: i32) -> Self {
 +        self.0.push_str(&format!("{}", other));
 +        self
 +    }
 +}
 +
 +struct Length(u8);
 +struct Meter;
 +
 +impl core::ops::Mul<Meter> for u8 {
 +    type Output = Length;
 +    fn mul(self, _: Meter) -> Length {
 +        Length(self)
 +    }
 +}
 +
 +#[allow(
 +    clippy::eq_op,
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::op_ref,
 +    clippy::double_parens
 +)]
 +#[warn(clippy::identity_op)]
 +#[rustfmt::skip]
 +fn main() {
 +    let x = 0;
 +
 +    x + 0;
 +    x + (1 - 1);
 +    x + 1;
 +    0 + x;
 +    1 + x;
 +    x - ZERO; //no error, as we skip lookups (for now)
 +    x | (0);
 +    ((ZERO)) | x; //no error, as we skip lookups (for now)
 +
 +    x * 1;
 +    1 * x;
 +    x / ONE; //no error, as we skip lookups (for now)
 +
 +    x / 2; //no false positive
 +
 +    x & NEG_ONE; //no error, as we skip lookups (for now)
 +    -1 & x;
 +
 +    let u: u8 = 0;
 +    u & 255;
 +
 +    1 << 0; // no error, this case is allowed, see issue 3430
 +    42 << 0;
 +    1 >> 0;
 +    42 >> 0;
 +    &x >> 0;
 +    x >> &0;
 +
 +    let mut a = A("".into());
 +    let b = a << 0; // no error: non-integer
 +
 +    1 * Meter; // no error: non-integer
++
++    2 % 3;
++    -2 % 3;
++    2 % -3 + x;
++    -2 % -3 + x;
++    x + 1 % 3;
++    (x + 1) % 3; // no error
++    4 % 3; // no error
++    4 % -3; // no error
 +}
index 0103cf5457e81a8a313dc1b78506497679903647,0000000000000000000000000000000000000000..706f01a3dd6c403b245ca8568cdb624def8f943a
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,112 @@@
- error: aborting due to 13 previous errors
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:37:5
 +   |
 +LL |     x + 0;
 +   |     ^^^^^
 +   |
 +   = note: `-D clippy::identity-op` implied by `-D warnings`
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:38:5
 +   |
 +LL |     x + (1 - 1);
 +   |     ^^^^^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:40:5
 +   |
 +LL |     0 + x;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:43:5
 +   |
 +LL |     x | (0);
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:46:5
 +   |
 +LL |     x * 1;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:47:5
 +   |
 +LL |     1 * x;
 +   |     ^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:53:5
 +   |
 +LL |     -1 & x;
 +   |     ^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `u`
 +  --> $DIR/identity_op.rs:56:5
 +   |
 +LL |     u & 255;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `42`
 +  --> $DIR/identity_op.rs:59:5
 +   |
 +LL |     42 << 0;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `1`
 +  --> $DIR/identity_op.rs:60:5
 +   |
 +LL |     1 >> 0;
 +   |     ^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `42`
 +  --> $DIR/identity_op.rs:61:5
 +   |
 +LL |     42 >> 0;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `&x`
 +  --> $DIR/identity_op.rs:62:5
 +   |
 +LL |     &x >> 0;
 +   |     ^^^^^^^
 +
 +error: the operation is ineffective. Consider reducing it to `x`
 +  --> $DIR/identity_op.rs:63:5
 +   |
 +LL |     x >> &0;
 +   |     ^^^^^^^
 +
++error: the operation is ineffective. Consider reducing it to `2`
++  --> $DIR/identity_op.rs:70:5
++   |
++LL |     2 % 3;
++   |     ^^^^^
++
++error: the operation is ineffective. Consider reducing it to `-2`
++  --> $DIR/identity_op.rs:71:5
++   |
++LL |     -2 % 3;
++   |     ^^^^^^
++
++error: the operation is ineffective. Consider reducing it to `2`
++  --> $DIR/identity_op.rs:72:5
++   |
++LL |     2 % -3 + x;
++   |     ^^^^^^
++
++error: the operation is ineffective. Consider reducing it to `-2`
++  --> $DIR/identity_op.rs:73:5
++   |
++LL |     -2 % -3 + x;
++   |     ^^^^^^^
++
++error: the operation is ineffective. Consider reducing it to `1`
++  --> $DIR/identity_op.rs:74:9
++   |
++LL |     x + 1 % 3;
++   |         ^^^^^
++
++error: aborting due to 18 previous errors
 +
index 639fecb8927bd322b4754c9fb00268107612e793,0000000000000000000000000000000000000000..2549c9f32f9049326e8ae416a651a81526a23b47
mode 100644,000000..100644
--- /dev/null
@@@ -1,117 -1,0 +1,117 @@@
- struct Kitten {}
 +#![warn(clippy::implicit_clone)]
 +#![allow(clippy::redundant_clone)]
 +use std::borrow::Borrow;
 +use std::ffi::{OsStr, OsString};
 +use std::path::PathBuf;
 +
 +fn return_owned_from_slice(slice: &[u32]) -> Vec<u32> {
 +    slice.to_owned()
 +}
 +
 +pub fn own_same<T>(v: T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_same_from_ref<T>(v: &T) -> T
 +where
 +    T: ToOwned<Owned = T>,
 +{
 +    v.to_owned()
 +}
 +
 +pub fn own_different<T, U>(v: T) -> U
 +where
 +    T: ToOwned<Owned = U>,
 +{
 +    v.to_owned()
 +}
 +
 +#[derive(Copy, Clone)]
- struct BorrowedKitten {}
++struct Kitten;
 +impl Kitten {
 +    // badly named method
 +    fn to_vec(self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +impl Borrow<BorrowedKitten> for Kitten {
 +    fn borrow(&self) -> &BorrowedKitten {
 +        static VALUE: BorrowedKitten = BorrowedKitten {};
 +        &VALUE
 +    }
 +}
 +
++struct BorrowedKitten;
 +impl ToOwned for BorrowedKitten {
 +    type Owned = Kitten;
 +    fn to_owned(&self) -> Kitten {
 +        Kitten {}
 +    }
 +}
 +
 +mod weird {
 +    #[allow(clippy::ptr_arg)]
 +    pub fn to_vec(v: &Vec<u32>) -> Vec<u32> {
 +        v.clone()
 +    }
 +}
 +
 +fn main() {
 +    let vec = vec![5];
 +    let _ = return_owned_from_slice(&vec);
 +    let _ = vec.to_owned();
 +    let _ = vec.to_vec();
 +
 +    let vec_ref = &vec;
 +    let _ = return_owned_from_slice(vec_ref);
 +    let _ = vec_ref.to_owned();
 +    let _ = vec_ref.to_vec();
 +
 +    // we expect no lint for this
 +    let _ = weird::to_vec(&vec);
 +
 +    // we expect no lints for this
 +    let slice: &[u32] = &[1, 2, 3, 4, 5];
 +    let _ = return_owned_from_slice(slice);
 +    let _ = slice.to_owned();
 +    let _ = slice.to_vec();
 +
 +    let str = "hello world".to_string();
 +    let _ = str.to_owned();
 +
 +    // testing w/ an arbitrary type
 +    let kitten = Kitten {};
 +    let _ = kitten.to_owned();
 +    let _ = own_same_from_ref(&kitten);
 +    // this shouln't lint
 +    let _ = kitten.to_vec();
 +
 +    // we expect no lints for this
 +    let borrowed = BorrowedKitten {};
 +    let _ = borrowed.to_owned();
 +
 +    let pathbuf = PathBuf::new();
 +    let _ = pathbuf.to_owned();
 +    let _ = pathbuf.to_path_buf();
 +
 +    let os_string = OsString::from("foo");
 +    let _ = os_string.to_owned();
 +    let _ = os_string.to_os_string();
 +
 +    // we expect no lints for this
 +    let os_str = OsStr::new("foo");
 +    let _ = os_str.to_owned();
 +    let _ = os_str.to_os_string();
 +
 +    // issue #8227
 +    let pathbuf_ref = &pathbuf;
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
 +    let _ = pathbuf_ref.to_path_buf();
 +    let pathbuf_ref = &pathbuf_ref;
 +    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
 +    let _ = pathbuf_ref.to_path_buf();
 +}
index ca8ca53c80c3f436956fef359df23a0778ebd111,0000000000000000000000000000000000000000..45a430edcb58998562e96b35e86d8c2a41db1e8b
mode 100644,000000..100644
--- /dev/null
@@@ -1,32 -1,0 +1,48 @@@
- #![allow(clippy::no_effect, clippy::unnecessary_operation)]
++#![feature(inline_const)]
 +#![warn(clippy::indexing_slicing)]
 +// We also check the out_of_bounds_indexing lint here, because it lints similar things and
 +// we want to avoid false positives.
 +#![warn(clippy::out_of_bounds_indexing)]
-     x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
-     x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
++#![allow(const_err, clippy::no_effect, clippy::unnecessary_operation)]
++
++const ARR: [i32; 2] = [1, 2];
++const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
++const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
++
++const fn idx() -> usize {
++    1
++}
++const fn idx4() -> usize {
++    4
++}
 +
 +fn main() {
 +    let x = [1, 2, 3, 4];
 +    let index: usize = 1;
 +    x[index];
-     x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
++    x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
 +
 +    x[0]; // Ok, should not produce stderr.
 +    x[3]; // Ok, should not produce stderr.
++    x[const { idx() }]; // Ok, should not produce stderr.
++    x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
++    const { &ARR[idx()] }; // Ok, should not produce stderr.
++    const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
 +
 +    let y = &x;
 +    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
 +    y[4]; // Ok, rustc will handle references too.
 +
 +    let v = vec![0; 5];
 +    v[0];
 +    v[10];
 +    v[1 << 3];
 +
 +    const N: usize = 15; // Out of bounds
 +    const M: usize = 3; // In bounds
++    x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
 +    x[M]; // Ok, should not produce stderr.
 +    v[N];
 +    v[M];
 +}
index 76ecec3348400f98e02de0356d316a619061c261,0000000000000000000000000000000000000000..83a36f407d5d877b18511182ca893781bbc628aa
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,64 @@@
-   --> $DIR/indexing_slicing_index.rs:10:5
++error[E0080]: evaluation of `main::{constant#3}::<&i32>` failed
++  --> $DIR/indexing_slicing_index.rs:31:14
++   |
++LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
++   |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
++
++error[E0080]: erroneous constant used
++  --> $DIR/indexing_slicing_index.rs:31:5
++   |
++LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
++   |     ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
++
 +error: indexing may panic
-   --> $DIR/indexing_slicing_index.rs:22:5
++  --> $DIR/indexing_slicing_index.rs:22:5
 +   |
 +LL |     x[index];
 +   |     ^^^^^^^^
 +   |
 +   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
-   --> $DIR/indexing_slicing_index.rs:23:5
++  --> $DIR/indexing_slicing_index.rs:38:5
 +   |
 +LL |     v[0];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
-   --> $DIR/indexing_slicing_index.rs:24:5
++  --> $DIR/indexing_slicing_index.rs:39:5
 +   |
 +LL |     v[10];
 +   |     ^^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
-   --> $DIR/indexing_slicing_index.rs:30:5
++  --> $DIR/indexing_slicing_index.rs:40:5
 +   |
 +LL |     v[1 << 3];
 +   |     ^^^^^^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
-   --> $DIR/indexing_slicing_index.rs:31:5
++  --> $DIR/indexing_slicing_index.rs:46:5
 +   |
 +LL |     v[N];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
 +error: indexing may panic
- error: aborting due to 6 previous errors
++  --> $DIR/indexing_slicing_index.rs:47:5
 +   |
 +LL |     v[M];
 +   |     ^^^^
 +   |
 +   = help: consider using `.get(n)` or `.get_mut(n)` instead
 +
++error: aborting due to 8 previous errors
 +
++For more information about this error, try `rustc --explain E0080`.
index b54147c94d192bea1c3ec58030aebd824b4f9bf2,0000000000000000000000000000000000000000..f23671c26e4cc55b43615564d8fd28148b3a6a98
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,31 @@@
- struct Foo {}
 +// run-rustfix
 +
 +#![warn(clippy::iter_nth_zero)]
 +use std::collections::HashSet;
 +
++struct Foo;
 +
 +impl Foo {
 +    fn nth(&self, index: usize) -> usize {
 +        index + 1
 +    }
 +}
 +
 +fn main() {
 +    let f = Foo {};
 +    f.nth(0); // lint does not apply here
 +
 +    let mut s = HashSet::new();
 +    s.insert(1);
 +    let _x = s.iter().next();
 +
 +    let mut s2 = HashSet::new();
 +    s2.insert(2);
 +    let mut iter = s2.iter();
 +    let _y = iter.next();
 +
 +    let mut s3 = HashSet::new();
 +    s3.insert(3);
 +    let mut iter2 = s3.iter();
 +    let _unwrapped = iter2.next().unwrap();
 +}
index b92c7d18adb4fb658484c29a640999e23907946b,0000000000000000000000000000000000000000..7c968d49845714574db74baaf2178eff36244467
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,31 @@@
- struct Foo {}
 +// run-rustfix
 +
 +#![warn(clippy::iter_nth_zero)]
 +use std::collections::HashSet;
 +
++struct Foo;
 +
 +impl Foo {
 +    fn nth(&self, index: usize) -> usize {
 +        index + 1
 +    }
 +}
 +
 +fn main() {
 +    let f = Foo {};
 +    f.nth(0); // lint does not apply here
 +
 +    let mut s = HashSet::new();
 +    s.insert(1);
 +    let _x = s.iter().nth(0);
 +
 +    let mut s2 = HashSet::new();
 +    s2.insert(2);
 +    let mut iter = s2.iter();
 +    let _y = iter.nth(0);
 +
 +    let mut s3 = HashSet::new();
 +    s3.insert(3);
 +    let mut iter2 = s3.iter();
 +    let _unwrapped = iter2.nth(0).unwrap();
 +}
index a9041671101b5006f437f516f3280545a6f67413,0000000000000000000000000000000000000000..56761ebbcb80bb0e5dcd595ba3ca0194b41829e2
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,51 @@@
 +// run-rustfix
 +#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
++#![allow(dead_code)]
 +
 +fn main() {
 +    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
 +
 +    let _: Option<String> = vec.iter().last().cloned();
 +
 +    let _: Option<String> = vec.iter().chain(vec.iter()).next().cloned();
 +
 +    let _: usize = vec.iter().filter(|x| x == &"2").count();
 +
 +    let _: Vec<_> = vec.iter().take(2).cloned().collect();
 +
 +    let _: Vec<_> = vec.iter().skip(2).cloned().collect();
 +
 +    let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned();
 +
 +    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
 +        .iter().flatten().cloned();
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().map(|x| x.len());
 +
 +    // This would fail if changed.
 +    let _ = vec.iter().cloned().map(|x| x + "2");
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().find(|x| x == "2");
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().all(|x| x.len() == 1);
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().any(|x| x.len() == 1);
 +
 +    // Should probably stay as it is.
 +    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
 +}
++
++// #8527
++fn cloned_flatten(x: Option<&Option<String>>) -> Option<String> {
++    x.cloned().flatten()
++}
index dd04e33a4b3aeedb8901b55a5d7e49f4d611852f,0000000000000000000000000000000000000000..98321d889b58273fd78a023d8933ad3af3f53074
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,53 @@@
 +// run-rustfix
 +#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
++#![allow(dead_code)]
 +
 +fn main() {
 +    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
 +
 +    let _: Option<String> = vec.iter().cloned().last();
 +
 +    let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
 +
 +    let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
 +
 +    let _: Vec<_> = vec.iter().cloned().take(2).collect();
 +
 +    let _: Vec<_> = vec.iter().cloned().skip(2).collect();
 +
 +    let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
 +
 +    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
 +        .iter()
 +        .cloned()
 +        .flatten();
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().map(|x| x.len());
 +
 +    // This would fail if changed.
 +    let _ = vec.iter().cloned().map(|x| x + "2");
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().find(|x| x == "2");
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().all(|x| x.len() == 1);
 +
 +    // Not implemented yet
 +    let _ = vec.iter().cloned().any(|x| x.len() == 1);
 +
 +    // Should probably stay as it is.
 +    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
 +}
++
++// #8527
++fn cloned_flatten(x: Option<&Option<String>>) -> Option<String> {
++    x.cloned().flatten()
++}
index e36b0e36fbdf98c6f4346682bd3a44df84ffac3a,0000000000000000000000000000000000000000..0582700fd16a8bde34e9b13c93786ad9e467c8e6
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
-   --> $DIR/iter_overeager_cloned.rs:7:29
 +error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead
-   --> $DIR/iter_overeager_cloned.rs:9:29
++  --> $DIR/iter_overeager_cloned.rs:8:29
 +   |
 +LL |     let _: Option<String> = vec.iter().cloned().last();
 +   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()`
 +   |
 +   = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings`
 +
 +error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead
-   --> $DIR/iter_overeager_cloned.rs:11:20
++  --> $DIR/iter_overeager_cloned.rs:10:29
 +   |
 +LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
 +   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()`
 +
 +error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead
-   --> $DIR/iter_overeager_cloned.rs:13:21
++  --> $DIR/iter_overeager_cloned.rs:12:20
 +   |
 +LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()`
 +   |
 +   = note: `-D clippy::redundant-clone` implied by `-D warnings`
 +
 +error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead
-   --> $DIR/iter_overeager_cloned.rs:15:21
++  --> $DIR/iter_overeager_cloned.rs:14:21
 +   |
 +LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()`
 +
 +error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead
-   --> $DIR/iter_overeager_cloned.rs:17:13
++  --> $DIR/iter_overeager_cloned.rs:16:21
 +   |
 +LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()`
 +
 +error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead
-   --> $DIR/iter_overeager_cloned.rs:19:13
++  --> $DIR/iter_overeager_cloned.rs:18:13
 +   |
 +LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()`
 +
 +error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead
++  --> $DIR/iter_overeager_cloned.rs:20:13
 +   |
 +LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
 +   |  _____________^
 +LL | |         .iter()
 +LL | |         .cloned()
 +LL | |         .flatten();
 +   | |__________________^
 +   |
 +help: try this
 +   |
 +LL ~     let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
 +LL ~         .iter().flatten().cloned();
 +   |
 +
 +error: aborting due to 7 previous errors
 +
index e4a2e9df4d7ba71d6ad41d0f9faa75d3f7ced853,0000000000000000000000000000000000000000..7601b5c66fa35057f69ea8cd989b5df689761e3c
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,66 @@@
- struct S {}
 +// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)"
 +// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
 +
 +#![warn(clippy::large_types_passed_by_value)]
 +
 +pub struct Large([u8; 2048]);
 +
 +#[derive(Clone, Copy)]
 +pub struct LargeAndCopy([u8; 2048]);
 +
 +pub struct Small([u8; 4]);
 +
 +#[derive(Clone, Copy)]
 +pub struct SmallAndCopy([u8; 4]);
 +
 +fn small(a: Small, b: SmallAndCopy) {}
 +fn not_copy(a: Large) {}
 +fn by_ref(a: &Large, b: &LargeAndCopy) {}
 +fn mutable(mut a: LargeAndCopy) {}
 +fn bad(a: LargeAndCopy) {}
 +pub fn bad_but_pub(a: LargeAndCopy) {}
 +
 +impl LargeAndCopy {
 +    fn self_is_ok(self) {}
 +    fn other_is_not_ok(self, other: LargeAndCopy) {}
 +    fn unless_other_can_change(self, mut other: LargeAndCopy) {}
 +    pub fn or_were_in_public(self, other: LargeAndCopy) {}
 +}
 +
 +trait LargeTypeDevourer {
 +    fn devoure_array(&self, array: [u8; 6666]);
 +    fn devoure_tuple(&self, tup: (LargeAndCopy, LargeAndCopy));
 +    fn devoure_array_and_tuple_wow(&self, array: [u8; 6666], tup: (LargeAndCopy, LargeAndCopy));
 +}
 +
 +pub trait PubLargeTypeDevourer {
 +    fn devoure_array_in_public(&self, array: [u8; 6666]);
 +}
 +
++struct S;
 +impl LargeTypeDevourer for S {
 +    fn devoure_array(&self, array: [u8; 6666]) {
 +        todo!();
 +    }
 +    fn devoure_tuple(&self, tup: (LargeAndCopy, LargeAndCopy)) {
 +        todo!();
 +    }
 +    fn devoure_array_and_tuple_wow(&self, array: [u8; 6666], tup: (LargeAndCopy, LargeAndCopy)) {
 +        todo!();
 +    }
 +}
 +
 +#[inline(always)]
 +fn foo_always(x: LargeAndCopy) {
 +    todo!();
 +}
 +#[inline(never)]
 +fn foo_never(x: LargeAndCopy) {
 +    todo!();
 +}
 +#[inline]
 +fn foo(x: LargeAndCopy) {
 +    todo!();
 +}
 +
 +fn main() {}
index e3561863c1e1ff7f00f1e52703e808cdb1c64e63,0000000000000000000000000000000000000000..bb162adc9adb26309f3b0968936a4e378ec0cfe4
mode 100644,000000..100644
--- /dev/null
@@@ -1,169 -1,0 +1,169 @@@
-         struct Bar {}
 +#![allow(unused)]
 +#![warn(clippy::let_and_return)]
 +
 +fn test() -> i32 {
 +    let _y = 0; // no warning
 +    let x = 5;
 +    x
 +}
 +
 +fn test_inner() -> i32 {
 +    if true {
 +        let x = 5;
 +        x
 +    } else {
 +        0
 +    }
 +}
 +
 +fn test_nowarn_1() -> i32 {
 +    let mut x = 5;
 +    x += 1;
 +    x
 +}
 +
 +fn test_nowarn_2() -> i32 {
 +    let x = 5;
 +    x + 1
 +}
 +
 +fn test_nowarn_3() -> (i32, i32) {
 +    // this should technically warn, but we do not compare complex patterns
 +    let (x, y) = (5, 9);
 +    (x, y)
 +}
 +
 +fn test_nowarn_4() -> i32 {
 +    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
 +    let x: i32 = 5;
 +    x
 +}
 +
 +fn test_nowarn_5(x: i16) -> u16 {
 +    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
 +    let x = x as u16;
 +    x
 +}
 +
 +// False positive example
 +trait Decode {
 +    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
 +    where
 +        Self: Sized;
 +}
 +
 +macro_rules! tuple_encode {
 +    ($($x:ident),*) => (
 +        impl<$($x: Decode),*> Decode for ($($x),*) {
 +            #[inline]
 +            #[allow(non_snake_case)]
 +            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
 +                // Shouldn't trigger lint
 +                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
 +            }
 +        }
 +    );
 +}
 +
 +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
 +
 +mod no_lint_if_stmt_borrows {
 +    mod issue_3792 {
 +        use std::io::{self, BufRead, Stdin};
 +
 +        fn read_line() -> String {
 +            let stdin = io::stdin();
 +            let line = stdin.lock().lines().next().unwrap().unwrap();
 +            line
 +        }
 +    }
 +
 +    mod issue_3324 {
 +        use std::cell::RefCell;
 +        use std::rc::{Rc, Weak};
 +
 +        fn test(value: Weak<RefCell<Bar>>) -> u32 {
 +            let value = value.upgrade().unwrap();
 +            let ret = value.borrow().baz();
 +            ret
 +        }
 +
++        struct Bar;
 +
 +        impl Bar {
 +            fn new() -> Self {
 +                Bar {}
 +            }
 +            fn baz(&self) -> u32 {
 +                0
 +            }
 +        }
 +
 +        fn main() {
 +            let a = Rc::new(RefCell::new(Bar::new()));
 +            let b = Rc::downgrade(&a);
 +            test(b);
 +        }
 +    }
 +
 +    mod free_function {
 +        struct Inner;
 +
 +        struct Foo<'a> {
 +            inner: &'a Inner,
 +        }
 +
 +        impl Drop for Foo<'_> {
 +            fn drop(&mut self) {}
 +        }
 +
 +        impl<'a> Foo<'a> {
 +            fn new(inner: &'a Inner) -> Self {
 +                Self { inner }
 +            }
 +
 +            fn value(&self) -> i32 {
 +                42
 +            }
 +        }
 +
 +        fn some_foo(inner: &Inner) -> Foo<'_> {
 +            Foo { inner }
 +        }
 +
 +        fn test() -> i32 {
 +            let x = Inner {};
 +            let value = some_foo(&x).value();
 +            value
 +        }
 +
 +        fn test2() -> i32 {
 +            let x = Inner {};
 +            let value = Foo::new(&x).value();
 +            value
 +        }
 +    }
 +}
 +
 +mod issue_5729 {
 +    use std::sync::Arc;
 +
 +    trait Foo {}
 +
 +    trait FooStorage {
 +        fn foo_cloned(&self) -> Arc<dyn Foo>;
 +    }
 +
 +    struct FooStorageImpl<T: Foo> {
 +        foo: Arc<T>,
 +    }
 +
 +    impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
 +        fn foo_cloned(&self) -> Arc<dyn Foo> {
 +            let clone = Arc::clone(&self.foo);
 +            clone
 +        }
 +    }
 +}
 +
 +fn main() {}
index a842e872a37b1f0fefcb21dad35b630ef75deaeb,0000000000000000000000000000000000000000..1edb77c748bfb715c0a3ddbcf2db2b19237238c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,95 @@@
- struct S {}
 +#![warn(clippy::let_underscore_must_use)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +// Debug implementations can fire this lint,
 +// so we shouldn't lint external macros
 +#[derive(Debug)]
 +struct Foo {
 +    field: i32,
 +}
 +
 +#[must_use]
 +fn f() -> u32 {
 +    0
 +}
 +
 +fn g() -> Result<u32, u32> {
 +    Ok(0)
 +}
 +
 +#[must_use]
 +fn l<T>(x: T) -> T {
 +    x
 +}
 +
 +fn h() -> u32 {
 +    0
 +}
 +
++struct S;
 +
 +impl S {
 +    #[must_use]
 +    pub fn f(&self) -> u32 {
 +        0
 +    }
 +
 +    pub fn g(&self) -> Result<u32, u32> {
 +        Ok(0)
 +    }
 +
 +    fn k(&self) -> u32 {
 +        0
 +    }
 +
 +    #[must_use]
 +    fn h() -> u32 {
 +        0
 +    }
 +
 +    fn p() -> Result<u32, u32> {
 +        Ok(0)
 +    }
 +}
 +
 +trait Trait {
 +    #[must_use]
 +    fn a() -> u32;
 +}
 +
 +impl Trait for S {
 +    fn a() -> u32 {
 +        0
 +    }
 +}
 +
 +fn main() {
 +    let _ = f();
 +    let _ = g();
 +    let _ = h();
 +    let _ = l(0_u32);
 +
 +    let s = S {};
 +
 +    let _ = s.f();
 +    let _ = s.g();
 +    let _ = s.k();
 +
 +    let _ = S::h();
 +    let _ = S::p();
 +
 +    let _ = S::a();
 +
 +    let _ = if true { Ok(()) } else { Err(()) };
 +
 +    let a = Result::<(), ()>::Ok(());
 +
 +    let _ = a.is_ok();
 +
 +    let _ = a.map(|_| ());
 +
 +    let _ = a;
 +
 +    #[allow(clippy::let_underscore_must_use)]
 +    let _ = a;
 +}
index 136cc96be70cafa57951fc7edd89c784892803b1,0000000000000000000000000000000000000000..b7e46a4a8ccc284cb9b8a5640e00bc944a762314
mode 100644,000000..100644
--- /dev/null
@@@ -1,110 -1,0 +1,110 @@@
- struct S {}
 +// run-rustfix
 +#![warn(clippy::manual_async_fn)]
 +#![allow(unused)]
 +
 +use std::future::Future;
 +
 +async fn fut() -> i32 { 42 }
 +
 +#[rustfmt::skip]
 +async fn fut2() -> i32 { 42 }
 +
 +#[rustfmt::skip]
 +async fn fut3() -> i32 { 42 }
 +
 +async fn empty_fut() {}
 +
 +#[rustfmt::skip]
 +async fn empty_fut2() {}
 +
 +#[rustfmt::skip]
 +async fn empty_fut3() {}
 +
 +async fn core_fut() -> i32 { 42 }
 +
 +// should be ignored
 +fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +    let _ = 42;
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn not_fut() -> i32 {
 +    42
 +}
 +
 +// should be ignored
 +async fn already_async() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
++struct S;
 +impl S {
 +    async fn inh_fut() -> i32 {
 +        // NOTE: this code is here just to check that the indentation is correct in the suggested fix
 +        let a = 42;
 +        let b = 21;
 +        if a < b {
 +            let c = 21;
 +            let d = 42;
 +            if c < d {
 +                let _ = 42;
 +            }
 +        }
 +        42
 +    }
 +
 +    // should be ignored
 +    fn not_fut(&self) -> i32 {
 +        42
 +    }
 +
 +    // should be ignored
 +    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +        let _ = 42;
 +        async move { 42 }
 +    }
 +
 +    // should be ignored
 +    async fn already_async(&self) -> impl Future<Output = i32> {
 +        async { 42 }
 +    }
 +}
 +
 +// Tests related to lifetime capture
 +
 +async fn elided(_: &i32) -> i32 { 42 }
 +
 +// should be ignored
 +fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 }
 +
 +// should be ignored
 +#[allow(clippy::needless_lifetimes)]
 +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +mod issue_5765 {
 +    use std::future::Future;
 +
 +    struct A;
 +    impl A {
 +        fn f(&self) -> impl Future<Output = ()> {
 +            async {}
 +        }
 +    }
 +
 +    fn test() {
 +        let _future = {
 +            let a = A;
 +            a.f()
 +        };
 +    }
 +}
 +
 +fn main() {}
index ddc453ffdb7500958c5e26cbf62a65a4859640f7,0000000000000000000000000000000000000000..b05429da6622500a9b35a606ed4967317419cb85
mode 100644,000000..100644
--- /dev/null
@@@ -1,130 -1,0 +1,130 @@@
- struct S {}
 +// run-rustfix
 +#![warn(clippy::manual_async_fn)]
 +#![allow(unused)]
 +
 +use std::future::Future;
 +
 +fn fut() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +#[rustfmt::skip]
 +fn fut2() ->impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +#[rustfmt::skip]
 +fn fut3()-> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +fn empty_fut() -> impl Future<Output = ()> {
 +    async {}
 +}
 +
 +#[rustfmt::skip]
 +fn empty_fut2() ->impl Future<Output = ()> {
 +    async {}
 +}
 +
 +#[rustfmt::skip]
 +fn empty_fut3()-> impl Future<Output = ()> {
 +    async {}
 +}
 +
 +fn core_fut() -> impl core::future::Future<Output = i32> {
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +    let _ = 42;
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn not_fut() -> i32 {
 +    42
 +}
 +
 +// should be ignored
 +async fn already_async() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
++struct S;
 +impl S {
 +    fn inh_fut() -> impl Future<Output = i32> {
 +        async {
 +            // NOTE: this code is here just to check that the indentation is correct in the suggested fix
 +            let a = 42;
 +            let b = 21;
 +            if a < b {
 +                let c = 21;
 +                let d = 42;
 +                if c < d {
 +                    let _ = 42;
 +                }
 +            }
 +            42
 +        }
 +    }
 +
 +    // should be ignored
 +    fn not_fut(&self) -> i32 {
 +        42
 +    }
 +
 +    // should be ignored
 +    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +        let _ = 42;
 +        async move { 42 }
 +    }
 +
 +    // should be ignored
 +    async fn already_async(&self) -> impl Future<Output = i32> {
 +        async { 42 }
 +    }
 +}
 +
 +// Tests related to lifetime capture
 +
 +fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +#[allow(clippy::needless_lifetimes)]
 +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +mod issue_5765 {
 +    use std::future::Future;
 +
 +    struct A;
 +    impl A {
 +        fn f(&self) -> impl Future<Output = ()> {
 +            async {}
 +        }
 +    }
 +
 +    fn test() {
 +        let _future = {
 +            let a = A;
 +            a.f()
 +        };
 +    }
 +}
 +
 +fn main() {}
index 05d6c56f2aca0a5dd63a3d635468800d0431a5e3,0000000000000000000000000000000000000000..7d68978216c9c67b8931a9562e96d3e7791930de
mode 100644,000000..100644
--- /dev/null
@@@ -1,181 -1,0 +1,181 @@@
-     struct S {}
 +// run-rustfix
 +#![allow(dead_code)]
 +#![allow(unused_variables, clippy::unnecessary_wraps)]
 +
 +fn option_unwrap_or() {
 +    // int case
 +    Some(1).unwrap_or(42);
 +
 +    // int case reversed
 +    Some(1).unwrap_or(42);
 +
 +    // richer none expr
 +    Some(1).unwrap_or(1 + 42);
 +
 +    // multiline case
 +    #[rustfmt::skip]
 +    Some(1).unwrap_or({
 +        42 + 42
 +            + 42 + 42 + 42
 +            + 42 + 42 + 42
 +    });
 +
 +    // string case
 +    Some("Bob").unwrap_or("Alice");
 +
 +    // don't lint
 +    match Some(1) {
 +        Some(i) => i + 2,
 +        None => 42,
 +    };
 +    match Some(1) {
 +        Some(i) => i,
 +        None => return,
 +    };
 +    for j in 0..4 {
 +        match Some(j) {
 +            Some(i) => i,
 +            None => continue,
 +        };
 +        match Some(j) {
 +            Some(i) => i,
 +            None => break,
 +        };
 +    }
 +
 +    // cases where the none arm isn't a constant expression
 +    // are not linted due to potential ownership issues
 +
 +    // ownership issue example, don't lint
 +    struct NonCopyable;
 +    let mut option: Option<NonCopyable> = None;
 +    match option {
 +        Some(x) => x,
 +        None => {
 +            option = Some(NonCopyable);
 +            // some more code ...
 +            option.unwrap()
 +        },
 +    };
 +
 +    // ownership issue example, don't lint
 +    let option: Option<&str> = None;
 +    match option {
 +        Some(s) => s,
 +        None => &format!("{} {}!", "hello", "world"),
 +    };
 +}
 +
 +fn result_unwrap_or() {
 +    // int case
 +    Ok::<i32, &str>(1).unwrap_or(42);
 +
 +    // int case, scrutinee is a binding
 +    let a = Ok::<i32, &str>(1);
 +    a.unwrap_or(42);
 +
 +    // int case, suggestion must surround Result expr with parentheses
 +    (Ok(1) as Result<i32, &str>).unwrap_or(42);
 +
 +    // method call case, suggestion must not surround Result expr `s.method()` with parentheses
++    struct S;
 +    impl S {
 +        fn method(self) -> Option<i32> {
 +            Some(42)
 +        }
 +    }
 +    let s = S {};
 +    s.method().unwrap_or(42);
 +
 +    // int case reversed
 +    Ok::<i32, &str>(1).unwrap_or(42);
 +
 +    // richer none expr
 +    Ok::<i32, &str>(1).unwrap_or(1 + 42);
 +
 +    // multiline case
 +    #[rustfmt::skip]
 +    Ok::<i32, &str>(1).unwrap_or({
 +        42 + 42
 +            + 42 + 42 + 42
 +            + 42 + 42 + 42
 +    });
 +
 +    // string case
 +    Ok::<&str, &str>("Bob").unwrap_or("Alice");
 +
 +    // don't lint
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i + 2,
 +        Err(_) => 42,
 +    };
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i,
 +        Err(_) => return,
 +    };
 +    for j in 0..4 {
 +        match Ok::<i32, &str>(j) {
 +            Ok(i) => i,
 +            Err(_) => continue,
 +        };
 +        match Ok::<i32, &str>(j) {
 +            Ok(i) => i,
 +            Err(_) => break,
 +        };
 +    }
 +
 +    // don't lint, Err value is used
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(s) => s,
 +    };
 +    // could lint, but unused_variables takes care of it
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(s) => "Bob",
 +    };
 +}
 +
 +// don't lint in const fn
 +const fn const_fn_option_unwrap_or() {
 +    match Some(1) {
 +        Some(s) => s,
 +        None => 0,
 +    };
 +}
 +
 +const fn const_fn_result_unwrap_or() {
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(_) => "Bob",
 +    };
 +}
 +
 +mod issue6965 {
 +    macro_rules! some_macro {
 +        () => {
 +            if 1 > 2 { Some(1) } else { None }
 +        };
 +    }
 +
 +    fn test() {
 +        let _ = some_macro!().unwrap_or(0);
 +    }
 +}
 +
 +use std::rc::Rc;
 +fn format_name(name: Option<&Rc<str>>) -> &str {
 +    match name {
 +        None => "<anon>",
 +        Some(name) => name,
 +    }
 +}
 +
 +fn implicit_deref_ref() {
 +    let _: &str = match Some(&"bye") {
 +        None => "hi",
 +        Some(s) => s,
 +    };
 +}
 +
 +fn main() {}
index 09f62c69b71de15b832c836a03c21829a78d501f,0000000000000000000000000000000000000000..b937fe6f977e5b7393d3423b9573ab5b903f89ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,223 -1,0 +1,223 @@@
-     struct S {}
 +// run-rustfix
 +#![allow(dead_code)]
 +#![allow(unused_variables, clippy::unnecessary_wraps)]
 +
 +fn option_unwrap_or() {
 +    // int case
 +    match Some(1) {
 +        Some(i) => i,
 +        None => 42,
 +    };
 +
 +    // int case reversed
 +    match Some(1) {
 +        None => 42,
 +        Some(i) => i,
 +    };
 +
 +    // richer none expr
 +    match Some(1) {
 +        Some(i) => i,
 +        None => 1 + 42,
 +    };
 +
 +    // multiline case
 +    #[rustfmt::skip]
 +    match Some(1) {
 +        Some(i) => i,
 +        None => {
 +            42 + 42
 +                + 42 + 42 + 42
 +                + 42 + 42 + 42
 +        }
 +    };
 +
 +    // string case
 +    match Some("Bob") {
 +        Some(i) => i,
 +        None => "Alice",
 +    };
 +
 +    // don't lint
 +    match Some(1) {
 +        Some(i) => i + 2,
 +        None => 42,
 +    };
 +    match Some(1) {
 +        Some(i) => i,
 +        None => return,
 +    };
 +    for j in 0..4 {
 +        match Some(j) {
 +            Some(i) => i,
 +            None => continue,
 +        };
 +        match Some(j) {
 +            Some(i) => i,
 +            None => break,
 +        };
 +    }
 +
 +    // cases where the none arm isn't a constant expression
 +    // are not linted due to potential ownership issues
 +
 +    // ownership issue example, don't lint
 +    struct NonCopyable;
 +    let mut option: Option<NonCopyable> = None;
 +    match option {
 +        Some(x) => x,
 +        None => {
 +            option = Some(NonCopyable);
 +            // some more code ...
 +            option.unwrap()
 +        },
 +    };
 +
 +    // ownership issue example, don't lint
 +    let option: Option<&str> = None;
 +    match option {
 +        Some(s) => s,
 +        None => &format!("{} {}!", "hello", "world"),
 +    };
 +}
 +
 +fn result_unwrap_or() {
 +    // int case
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i,
 +        Err(_) => 42,
 +    };
 +
 +    // int case, scrutinee is a binding
 +    let a = Ok::<i32, &str>(1);
 +    match a {
 +        Ok(i) => i,
 +        Err(_) => 42,
 +    };
 +
 +    // int case, suggestion must surround Result expr with parentheses
 +    match Ok(1) as Result<i32, &str> {
 +        Ok(i) => i,
 +        Err(_) => 42,
 +    };
 +
 +    // method call case, suggestion must not surround Result expr `s.method()` with parentheses
++    struct S;
 +    impl S {
 +        fn method(self) -> Option<i32> {
 +            Some(42)
 +        }
 +    }
 +    let s = S {};
 +    match s.method() {
 +        Some(i) => i,
 +        None => 42,
 +    };
 +
 +    // int case reversed
 +    match Ok::<i32, &str>(1) {
 +        Err(_) => 42,
 +        Ok(i) => i,
 +    };
 +
 +    // richer none expr
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i,
 +        Err(_) => 1 + 42,
 +    };
 +
 +    // multiline case
 +    #[rustfmt::skip]
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i,
 +        Err(_) => {
 +            42 + 42
 +                + 42 + 42 + 42
 +                + 42 + 42 + 42
 +        }
 +    };
 +
 +    // string case
 +    match Ok::<&str, &str>("Bob") {
 +        Ok(i) => i,
 +        Err(_) => "Alice",
 +    };
 +
 +    // don't lint
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i + 2,
 +        Err(_) => 42,
 +    };
 +    match Ok::<i32, &str>(1) {
 +        Ok(i) => i,
 +        Err(_) => return,
 +    };
 +    for j in 0..4 {
 +        match Ok::<i32, &str>(j) {
 +            Ok(i) => i,
 +            Err(_) => continue,
 +        };
 +        match Ok::<i32, &str>(j) {
 +            Ok(i) => i,
 +            Err(_) => break,
 +        };
 +    }
 +
 +    // don't lint, Err value is used
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(s) => s,
 +    };
 +    // could lint, but unused_variables takes care of it
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(s) => "Bob",
 +    };
 +}
 +
 +// don't lint in const fn
 +const fn const_fn_option_unwrap_or() {
 +    match Some(1) {
 +        Some(s) => s,
 +        None => 0,
 +    };
 +}
 +
 +const fn const_fn_result_unwrap_or() {
 +    match Ok::<&str, &str>("Alice") {
 +        Ok(s) => s,
 +        Err(_) => "Bob",
 +    };
 +}
 +
 +mod issue6965 {
 +    macro_rules! some_macro {
 +        () => {
 +            if 1 > 2 { Some(1) } else { None }
 +        };
 +    }
 +
 +    fn test() {
 +        let _ = match some_macro!() {
 +            Some(val) => val,
 +            None => 0,
 +        };
 +    }
 +}
 +
 +use std::rc::Rc;
 +fn format_name(name: Option<&Rc<str>>) -> &str {
 +    match name {
 +        None => "<anon>",
 +        Some(name) => name,
 +    }
 +}
 +
 +fn implicit_deref_ref() {
 +    let _: &str = match Some(&"bye") {
 +        None => "hi",
 +        Some(s) => s,
 +    };
 +}
 +
 +fn main() {}
index 4a1452b25f343923c71059722e6d0fe3d32dcc6f,0000000000000000000000000000000000000000..2256e51f2d09c49550f3f6ccd7c74034c1b82ab8
mode 100644,000000..100644
--- /dev/null
@@@ -1,23 -1,0 +1,25 @@@
 +// run-rustfix
 +#![warn(clippy::map_identity)]
 +#![allow(clippy::needless_return)]
 +
 +fn main() {
 +    let x: [u16; 3] = [1, 2, 3];
 +    // should lint
 +    let _: Vec<_> = x.iter().map(not_identity).collect();
 +    let _: Vec<_> = x.iter().collect();
 +    let _: Option<u8> = Some(3);
 +    let _: Result<i8, f32> = Ok(-3);
 +    // should not lint
 +    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
 +    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
 +    let _: Option<u8> = None.map(|x: u8| x - 1);
 +    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
 +        return x + 3;
 +    });
++    let _: Result<u32, u32> = Ok(1);
++    let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
 +}
 +
 +fn not_identity(x: &u16) -> u16 {
 +    *x
 +}
index 65c7e6e1ea554a7db9d691ce237337a450e2c3ed,0000000000000000000000000000000000000000..ccfdc9ea76d522ce6d888d04aafdbd401fda0959
mode 100644,000000..100644
--- /dev/null
@@@ -1,25 -1,0 +1,27 @@@
 +// run-rustfix
 +#![warn(clippy::map_identity)]
 +#![allow(clippy::needless_return)]
 +
 +fn main() {
 +    let x: [u16; 3] = [1, 2, 3];
 +    // should lint
 +    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
 +    let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
 +    let _: Option<u8> = Some(3).map(|x| x);
 +    let _: Result<i8, f32> = Ok(-3).map(|x| {
 +        return x;
 +    });
 +    // should not lint
 +    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
 +    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
 +    let _: Option<u8> = None.map(|x: u8| x - 1);
 +    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
 +        return x + 3;
 +    });
++    let _: Result<u32, u32> = Ok(1).map_err(|a| a);
++    let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
 +}
 +
 +fn not_identity(x: &u16) -> u16 {
 +    *x
 +}
index e4a0320cbda55721fffd017087d3db81a0868937,0000000000000000000000000000000000000000..b6a77281f6de2e6424c76bd23f1dab64e99469a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,43 @@@
- error: aborting due to 5 previous errors
 +error: unnecessary map of the identity function
 +  --> $DIR/map_identity.rs:8:47
 +   |
 +LL |     let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
 +   |                                               ^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 +   |
 +   = note: `-D clippy::map-identity` implied by `-D warnings`
 +
 +error: unnecessary map of the identity function
 +  --> $DIR/map_identity.rs:9:57
 +   |
 +LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
 +   |                                                         ^^^^^^^^^^^ help: remove the call to `map`
 +
 +error: unnecessary map of the identity function
 +  --> $DIR/map_identity.rs:9:29
 +   |
 +LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
 +   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 +
 +error: unnecessary map of the identity function
 +  --> $DIR/map_identity.rs:10:32
 +   |
 +LL |     let _: Option<u8> = Some(3).map(|x| x);
 +   |                                ^^^^^^^^^^^ help: remove the call to `map`
 +
 +error: unnecessary map of the identity function
 +  --> $DIR/map_identity.rs:11:36
 +   |
 +LL |       let _: Result<i8, f32> = Ok(-3).map(|x| {
 +   |  ____________________________________^
 +LL | |         return x;
 +LL | |     });
 +   | |______^ help: remove the call to `map`
 +
++error: unnecessary map of the identity function
++  --> $DIR/map_identity.rs:21:36
++   |
++LL |     let _: Result<u32, u32> = Ok(1).map_err(|a| a);
++   |                                    ^^^^^^^^^^^^^^^ help: remove the call to `map_err`
++
++error: aborting due to 6 previous errors
 +
index 9a74da4e3b8b641ef4387246ab1f24ea7800de4d,0000000000000000000000000000000000000000..e7f07b50f3ab1fbad149d309b3da9c67bd007950
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
- struct Mappable {}
 +#![allow(unused)]
++struct Mappable;
 +
 +impl Mappable {
 +    pub fn map(&self) {}
 +}
 +
 +fn main() {
 +    let m = Mappable {};
 +    m.map();
 +}
index c5f221220ece7374caeab1c21dc14c35e6b8751e,0000000000000000000000000000000000000000..f83c3e0e281ca29ccad4714e491feb26a6b18f5e
mode 100644,000000..100644
--- /dev/null
@@@ -1,201 -1,0 +1,213 @@@
-     struct Foo {}
 +#![allow(clippy::redundant_clone)]
 +#![feature(custom_inner_attributes)]
 +#![clippy::msrv = "1.0.0"]
 +
 +use std::ops::{Deref, RangeFrom};
 +
 +fn approx_const() {
 +    let log2_10 = 3.321928094887362;
 +    let log10_2 = 0.301029995663981;
 +}
 +
 +fn cloned_instead_of_copied() {
 +    let _ = [1].iter().cloned();
 +}
 +
 +fn option_as_ref_deref() {
 +    let mut opt = Some(String::from("123"));
 +
 +    let _ = opt.as_ref().map(String::as_str);
 +    let _ = opt.as_ref().map(|x| x.as_str());
 +    let _ = opt.as_mut().map(String::as_mut_str);
 +    let _ = opt.as_mut().map(|x| x.as_mut_str());
 +}
 +
 +fn match_like_matches() {
 +    let _y = match Some(5) {
 +        Some(0) => true,
 +        _ => false,
 +    };
 +}
 +
 +fn match_same_arms() {
 +    match (1, 2, 3) {
 +        (1, .., 3) => 42,
 +        (.., 3) => 42, //~ ERROR match arms have same body
 +        _ => 0,
 +    };
 +}
 +
 +fn match_same_arms2() {
 +    let _ = match Some(42) {
 +        Some(_) => 24,
 +        None => 24, //~ ERROR match arms have same body
 +    };
 +}
 +
 +pub fn manual_strip_msrv() {
 +    let s = "hello, world!";
 +    if s.starts_with("hello, ") {
 +        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +    }
 +}
 +
 +pub fn redundant_fieldnames() {
 +    let start = 0;
 +    let _ = RangeFrom { start: start };
 +}
 +
 +pub fn redundant_static_lifetime() {
 +    const VAR_ONE: &'static str = "Test constant #1";
 +}
 +
 +pub fn checked_conversion() {
 +    let value: i64 = 42;
 +    let _ = value <= (u32::max_value() as i64) && value >= 0;
 +    let _ = value <= (u32::MAX as i64) && value >= 0;
 +}
 +
 +pub struct FromOverInto(String);
 +
 +impl Into<FromOverInto> for String {
 +    fn into(self) -> FromOverInto {
 +        FromOverInto(self)
 +    }
 +}
 +
 +pub fn filter_map_next() {
 +    let a = ["1", "lol", "3", "NaN", "5"];
 +
 +    #[rustfmt::skip]
 +    let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
 +        .into_iter()
 +        .filter_map(|x| {
 +            if x == 2 {
 +                Some(x * 2)
 +            } else {
 +                None
 +            }
 +        })
 +        .next();
 +}
 +
 +#[allow(clippy::no_effect)]
 +#[allow(clippy::short_circuit_statement)]
 +#[allow(clippy::unnecessary_operation)]
 +pub fn manual_range_contains() {
 +    let x = 5;
 +    x >= 8 && x < 12;
 +}
 +
 +pub fn use_self() {
++    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +        fn test() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +fn replace_with_default() {
 +    let mut s = String::from("foo");
 +    let _ = std::mem::replace(&mut s, String::default());
 +}
 +
 +fn map_unwrap_or() {
 +    let opt = Some(1);
 +
 +    // Check for `option.map(_).unwrap_or(_)` use.
 +    // Single line case.
 +    let _ = opt
 +        .map(|x| x + 1)
 +        // Should lint even though this call is on a separate line.
 +        .unwrap_or(0);
 +}
 +
 +// Could be const
 +fn missing_const_for_fn() -> i32 {
 +    1
 +}
 +
 +fn unnest_or_patterns() {
 +    struct TS(u8, u8);
 +    if let TS(0, x) | TS(1, x) = TS(0, 0) {}
 +}
 +
 +#[cfg_attr(rustfmt, rustfmt_skip)]
 +fn deprecated_cfg_attr() {}
 +
 +#[warn(clippy::cast_lossless)]
 +fn int_from_bool() -> u8 {
 +    true as u8
 +}
 +
++fn err_expect() {
++    let x: Result<u32, &str> = Ok(10);
++    x.err().expect("Testing expect_err");
++}
++
++fn cast_abs_to_unsigned() {
++    let x: i32 = 10;
++    assert_eq!(10u32, x.abs() as u32);
++}
++
 +fn main() {
 +    filter_map_next();
 +    checked_conversion();
 +    redundant_fieldnames();
 +    redundant_static_lifetime();
 +    option_as_ref_deref();
 +    match_like_matches();
 +    match_same_arms();
 +    match_same_arms2();
 +    manual_strip_msrv();
 +    manual_range_contains();
 +    use_self();
 +    replace_with_default();
 +    map_unwrap_or();
 +    missing_const_for_fn();
 +    unnest_or_patterns();
 +    int_from_bool();
++    err_expect();
++    cast_abs_to_unsigned();
 +}
 +
 +mod just_under_msrv {
 +    #![feature(custom_inner_attributes)]
 +    #![clippy::msrv = "1.44.0"]
 +
 +    fn main() {
 +        let s = "hello, world!";
 +        if s.starts_with("hello, ") {
 +            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +        }
 +    }
 +}
 +
 +mod meets_msrv {
 +    #![feature(custom_inner_attributes)]
 +    #![clippy::msrv = "1.45.0"]
 +
 +    fn main() {
 +        let s = "hello, world!";
 +        if s.starts_with("hello, ") {
 +            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +        }
 +    }
 +}
 +
 +mod just_above_msrv {
 +    #![feature(custom_inner_attributes)]
 +    #![clippy::msrv = "1.46.0"]
 +
 +    fn main() {
 +        let s = "hello, world!";
 +        if s.starts_with("hello, ") {
 +            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +        }
 +    }
 +}
index 6b3fdb0844b49e1a0e2dd23dfc6c0fc70dcc4942,0000000000000000000000000000000000000000..de225eb740d03dc9024df7276c6e72d9d399e760
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,37 @@@
-   --> $DIR/min_rust_version_attr.rs:186:24
 +error: stripping a prefix manually
-   --> $DIR/min_rust_version_attr.rs:185:9
++  --> $DIR/min_rust_version_attr.rs:198:24
 +   |
 +LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +   |                        ^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::manual-strip` implied by `-D warnings`
 +note: the prefix was tested here
-   --> $DIR/min_rust_version_attr.rs:198:24
++  --> $DIR/min_rust_version_attr.rs:197:9
 +   |
 +LL |         if s.starts_with("hello, ") {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +help: try using the `strip_prefix` method
 +   |
 +LL ~         if let Some(<stripped>) = s.strip_prefix("hello, ") {
 +LL ~             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
 +   |
 +
 +error: stripping a prefix manually
-   --> $DIR/min_rust_version_attr.rs:197:9
++  --> $DIR/min_rust_version_attr.rs:210:24
 +   |
 +LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
 +   |                        ^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: the prefix was tested here
++  --> $DIR/min_rust_version_attr.rs:209:9
 +   |
 +LL |         if s.starts_with("hello, ") {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +help: try using the `strip_prefix` method
 +   |
 +LL ~         if let Some(<stripped>) = s.strip_prefix("hello, ") {
 +LL ~             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
 +   |
 +
 +error: aborting due to 2 previous errors
 +
index b73b24b8e0a3b9b50fc6eaaf7b3e68d95168d324,0000000000000000000000000000000000000000..07f8e3888c998274b8fa240a6fac1e72fd7f2e10
mode 100644,000000..100644
--- /dev/null
@@@ -1,66 -1,0 +1,66 @@@
- struct Foo {} // ok
- pub struct PubFoo {} // ok
 +#![warn(clippy::missing_inline_in_public_items)]
 +#![crate_type = "dylib"]
 +// When denying at the crate level, be sure to not get random warnings from the
 +// injected intrinsics by the compiler.
 +#![allow(dead_code, non_snake_case)]
 +
 +type Typedef = String;
 +pub type PubTypedef = String;
 +
- pub struct S {}
++struct Foo; // ok
++pub struct PubFoo; // ok
 +enum FooE {} // ok
 +pub enum PubFooE {} // ok
 +
 +mod module {} // ok
 +pub mod pub_module {} // ok
 +
 +fn foo() {}
 +pub fn pub_foo() {} // missing #[inline]
 +#[inline]
 +pub fn pub_foo_inline() {} // ok
 +#[inline(always)]
 +pub fn pub_foo_inline_always() {} // ok
 +
 +#[allow(clippy::missing_inline_in_public_items)]
 +pub fn pub_foo_no_inline() {}
 +
 +trait Bar {
 +    fn Bar_a(); // ok
 +    fn Bar_b() {} // ok
 +}
 +
 +pub trait PubBar {
 +    fn PubBar_a(); // ok
 +    fn PubBar_b() {} // missing #[inline]
 +    #[inline]
 +    fn PubBar_c() {} // ok
 +}
 +
 +// none of these need inline because Foo is not exported
 +impl PubBar for Foo {
 +    fn PubBar_a() {} // ok
 +    fn PubBar_b() {} // ok
 +    fn PubBar_c() {} // ok
 +}
 +
 +// all of these need inline because PubFoo is exported
 +impl PubBar for PubFoo {
 +    fn PubBar_a() {} // missing #[inline]
 +    fn PubBar_b() {} // missing #[inline]
 +    fn PubBar_c() {} // missing #[inline]
 +}
 +
 +// do not need inline because Foo is not exported
 +impl Foo {
 +    fn FooImpl() {} // ok
 +}
 +
 +// need inline because PubFoo is exported
 +impl PubFoo {
 +    pub fn PubFooImpl() {} // missing #[inline]
 +}
 +
 +// do not lint this since users cannot control the external code
 +#[derive(Debug)]
++pub struct S;
index f5908cb5701fbe9a3e62a1779951aad18baf6af6,0000000000000000000000000000000000000000..ebaa77cc283e0420cd0c7f17085cf998524e6b33
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,18 @@@
-     pub struct FooCake {}
 +// compile-flags: --test
 +
 +#![warn(clippy::module_name_repetitions)]
 +#![allow(dead_code)]
 +
 +mod foo {
 +    pub fn foo() {}
 +    pub fn foo_bar() {}
 +    pub fn bar_foo() {}
++    pub struct FooCake;
 +    pub enum CakeFoo {}
 +    pub struct Foo7Bar;
 +
 +    // Should not warn
 +    pub struct Foobar;
 +}
 +
 +fn main() {}
index bdd217a969c05acfcee5efe23b2e111b72451b62,0000000000000000000000000000000000000000..3f343a3e430185f8ca8535370c363b1f2c308ace
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
- LL |     pub struct FooCake {}
-    |     ^^^^^^^^^^^^^^^^^^^^^
 +error: item name starts with its containing module's name
 +  --> $DIR/module_name_repetitions.rs:8:5
 +   |
 +LL |     pub fn foo_bar() {}
 +   |     ^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
 +
 +error: item name ends with its containing module's name
 +  --> $DIR/module_name_repetitions.rs:9:5
 +   |
 +LL |     pub fn bar_foo() {}
 +   |     ^^^^^^^^^^^^^^^^^^^
 +
 +error: item name starts with its containing module's name
 +  --> $DIR/module_name_repetitions.rs:10:5
 +   |
++LL |     pub struct FooCake;
++   |     ^^^^^^^^^^^^^^^^^^^
 +
 +error: item name ends with its containing module's name
 +  --> $DIR/module_name_repetitions.rs:11:5
 +   |
 +LL |     pub enum CakeFoo {}
 +   |     ^^^^^^^^^^^^^^^^^^^
 +
 +error: item name starts with its containing module's name
 +  --> $DIR/module_name_repetitions.rs:12:5
 +   |
 +LL |     pub struct Foo7Bar;
 +   |     ^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 5 previous errors
 +
index 047a29fa1e327201d12847ff71452f51cea4ec9d,0000000000000000000000000000000000000000..3ebe46bc5be7c5b8b4108f4477b70663a5734b38
mode 100644,000000..100644
--- /dev/null
@@@ -1,37 -1,0 +1,42 @@@
- #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)]
 +#![warn(clippy::modulo_arithmetic)]
++#![allow(
++    clippy::no_effect,
++    clippy::unnecessary_operation,
++    clippy::modulo_one,
++    clippy::identity_op
++)]
 +
 +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 64335f35f0f82d997a2b4e1e14f52fa9af68df28,0000000000000000000000000000000000000000..11b5f77461ba2e93b94779543f77b8770ffbf440
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,156 @@@
-   --> $DIR/modulo_arithmetic_integral_const.rs:6:5
 +error: you are using modulo operator on constants with different signs: `-1 % 2`
-   --> $DIR/modulo_arithmetic_integral_const.rs:7:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:11: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:8:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:12: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:9:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:13: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:10:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:14: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:12:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:15: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:13:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:17: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:14:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:18: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:15:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:19: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:16:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:20: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:17:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:21: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:18:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:22: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:19:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:23: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:20:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:24: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:21:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:25: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:22:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:26: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:23:5
++  --> $DIR/modulo_arithmetic_integral_const.rs:27: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:28: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 ad0d694a2174a3a125393790d5767a81afd9c98d,0000000000000000000000000000000000000000..02b43cce2bd4c5b77a46ee1d73088f83ad8732ca
mode 100644,000000..100644
--- /dev/null
@@@ -1,46 -1,0 +1,46 @@@
-             struct S1 {}
 +// aux-build:proc_macro_attr.rs
 +
 +#![warn(clippy::needless_arbitrary_self_type)]
 +
 +#[macro_use]
 +extern crate proc_macro_attr;
 +
 +mod issue_6089 {
 +    // Check that we don't lint if the `self` parameter comes from expansion
 +
 +    macro_rules! test_from_expansion {
 +        () => {
 +            trait T1 {
 +                fn test(self: &Self);
 +            }
 +
-     struct S2 {}
++            struct S1;
 +
 +            impl T1 for S1 {
 +                fn test(self: &Self) {}
 +            }
 +        };
 +    }
 +
 +    test_from_expansion!();
 +
 +    // If only the lifetime name comes from expansion we will lint, but the suggestion will have
 +    // placeholders and will not be applied automatically, as we can't reliably know the original name.
 +    // This specific case happened with async_trait.
 +
 +    trait T2 {
 +        fn call_with_mut_self(&mut self);
 +    }
 +
++    struct S2;
 +
 +    // The method's signature will be expanded to:
 +    //  fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
 +    #[rename_my_lifetimes]
 +    impl T2 for S2 {
 +        #[allow(clippy::needless_lifetimes)]
 +        fn call_with_mut_self(self: &mut Self) {}
 +    }
 +}
 +
 +fn main() {}
index f3eafe8e9279e2167bb2d7dfe7f94dd5deb3b15a,0000000000000000000000000000000000000000..1456204ca8692fdd79f65e4540946674c2d9f7e2
mode 100644,000000..100644
--- /dev/null
@@@ -1,421 -1,0 +1,421 @@@
-     struct Bar {}
 +#![warn(clippy::needless_lifetimes)]
 +#![allow(
 +    dead_code,
 +    clippy::boxed_local,
 +    clippy::needless_pass_by_value,
 +    clippy::unnecessary_wraps,
 +    dyn_drop
 +)]
 +
 +fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 +
 +fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
 +
 +// No error; same lifetime on two params.
 +fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
 +
 +// No error; static involved.
 +fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
 +
 +fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
 +
 +fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error; multiple input refs.
 +fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error; multiple input refs.
 +fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error; multiple input refs
 +async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
 +    args.get(0).cloned()
 +}
 +
 +// No error; static involved.
 +fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error.
 +fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
 +    Ok(x)
 +}
 +
 +// No error; two input refs.
 +fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
 +    x.unwrap()
 +}
 +
 +fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
 +    Ok(x)
 +}
 +
 +// Where-clause, but without lifetimes.
 +fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
 +where
 +    T: Copy,
 +{
 +    Ok(x)
 +}
 +
 +type Ref<'r> = &'r u8;
 +
 +// No error; same lifetime on two params.
 +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
 +
 +fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
 +
 +// No error; bounded lifetime.
 +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
 +
 +// No error; bounded lifetime.
 +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
 +where
 +    'b: 'a,
 +{
 +}
 +
 +struct Lt<'a, I: 'static> {
 +    x: &'a I,
 +}
 +
 +// No error; fn bound references `'a`.
 +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
 +where
 +    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
 +{
 +    unreachable!()
 +}
 +
 +fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
 +where
 +    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
 +{
 +    unreachable!()
 +}
 +
 +// No error; see below.
 +fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
 +    f(x);
 +}
 +
 +fn fn_bound_3_cannot_elide() {
 +    let x = 42;
 +    let p = &x;
 +    let mut q = &x;
 +    // This will fail if we elide lifetimes of `fn_bound_3`.
 +    fn_bound_3(p, |y| q = y);
 +}
 +
 +// No error; multiple input refs.
 +fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
 +    if cond { x } else { f() }
 +}
 +
 +struct X {
 +    x: u8,
 +}
 +
 +impl X {
 +    fn self_and_out<'s>(&'s self) -> &'s u8 {
 +        &self.x
 +    }
 +
 +    // No error; multiple input refs.
 +    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
 +        &self.x
 +    }
 +
 +    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
 +
 +    // No error; same lifetimes on two params.
 +    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
 +}
 +
 +struct Foo<'a>(&'a u8);
 +
 +impl<'a> Foo<'a> {
 +    // No error; lifetime `'a` not defined in method.
 +    fn self_shared_lifetime(&self, _: &'a u8) {}
 +    // No error; bounds exist.
 +    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
 +}
 +
 +fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
 +    unimplemented!()
 +}
 +
 +fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
 +fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
 +fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes.
 +fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +trait WithLifetime<'a> {}
 +
 +type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
 +
 +// Should not warn because it won't build without the lifetime.
 +fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// Should warn because there is no lifetime on `Drop`, so this would be
 +// unambiguous if we elided the lifetime.
 +fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
 +    unimplemented!()
 +}
 +
 +type FooAlias<'a> = Foo<'a>;
 +
 +fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
 +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
 +fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes.
 +fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
 +    unimplemented!()
 +}
 +
 +fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
 +    unimplemented!()
 +}
 +
 +fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
 +    unimplemented!()
 +}
 +fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
 +    unimplemented!()
 +}
 +
 +// Don't warn on these; see issue #292.
 +fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
 +    unimplemented!()
 +}
 +
 +// See issue #740.
 +struct Test {
 +    vec: Vec<usize>,
 +}
 +
 +impl Test {
 +    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
 +        unimplemented!()
 +    }
 +}
 +
 +trait LintContext<'a> {}
 +
 +fn f<'a, T: LintContext<'a>>(_: &T) {}
 +
 +fn test<'a>(x: &'a [u8]) -> u8 {
 +    let y: &'a u8 = &x[5];
 +    *y
 +}
 +
 +// Issue #3284: give hint regarding lifetime in return type.
 +struct Cow<'a> {
 +    x: &'a str,
 +}
 +fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
 +    unimplemented!()
 +}
 +
 +// Make sure we still warn on implementations
 +mod issue4291 {
 +    trait BadTrait {
 +        fn needless_lt<'a>(x: &'a u8) {}
 +    }
 +
 +    impl BadTrait for () {
 +        fn needless_lt<'a>(_x: &'a u8) {}
 +    }
 +}
 +
 +mod issue2944 {
 +    trait Foo {}
++    struct Bar;
 +    struct Baz<'a> {
 +        bar: &'a Bar,
 +    }
 +
 +    impl<'a> Foo for Baz<'a> {}
 +    impl Bar {
 +        fn baz<'a>(&'a self) -> impl Foo + 'a {
 +            Baz { bar: self }
 +        }
 +    }
 +}
 +
 +mod nested_elision_sites {
 +    // issue #issue2944
 +
 +    // closure trait bounds subject to nested elision
 +    // don't lint because they refer to outer lifetimes
 +    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
 +        move || i
 +    }
 +    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
 +        move || i
 +    }
 +    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
 +        move || i
 +    }
 +
 +    // don't lint
 +    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
 +        f()
 +    }
 +    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
 +        move || i
 +    }
 +    // lint
 +    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
 +        f(i)
 +    }
 +    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
 +        f()
 +    }
 +    // lint
 +    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
 +    where
 +        T: Fn() -> &'a i32,
 +    {
 +        f()
 +    }
 +    // lint
 +    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
 +    where
 +        T: Fn(&i32) -> &i32,
 +    {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
 +        f(i)
 +    }
 +    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
 +        |i| i
 +    }
 +    // lint
 +    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
 +        |f| 42
 +    }
 +    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
 +        |f| ()
 +    }
 +
 +    // lint
 +    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
 +        |f| 42
 +    }
 +    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
 +        |f| ()
 +    }
 +}
 +
 +mod issue6159 {
 +    use std::ops::Deref;
 +    pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
 +    where
 +        T: Deref,
 +        F: FnOnce(&'a T::Target) -> R,
 +    {
 +        f(x.deref())
 +    }
 +}
 +
 +mod issue7296 {
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    struct Foo;
 +    impl Foo {
 +        fn implicit<'a>(&'a self) -> &'a () {
 +            &()
 +        }
 +        fn implicit_mut<'a>(&'a mut self) -> &'a () {
 +            &()
 +        }
 +
 +        fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
 +            &()
 +        }
 +        fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
 +            &()
 +        }
 +
 +        fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
 +            &()
 +        }
 +    }
 +
 +    trait Bar {
 +        fn implicit<'a>(&'a self) -> &'a ();
 +        fn implicit_provided<'a>(&'a self) -> &'a () {
 +            &()
 +        }
 +
 +        fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
 +        fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
 +            &()
 +        }
 +
 +        fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
 +        fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
 +            &()
 +        }
 +    }
 +}
 +
 +fn main() {}
index ece18ad737fdad5264a22085a2dcfb94003a83b8,0000000000000000000000000000000000000000..9ccccaa1725a65dc8867a1a48e9698c811682886
mode 100644,000000..100644
--- /dev/null
@@@ -1,83 -1,0 +1,197 @@@
- enum Choice {
 +// run-rustfix
 +#![warn(clippy::needless_match)]
 +#![allow(clippy::manual_map)]
 +#![allow(dead_code)]
 +
 +#[derive(Clone, Copy)]
- #[allow(unused_mut)]
++enum Simple {
 +    A,
 +    B,
 +    C,
 +    D,
 +}
 +
-     let mut i = 10;
 +fn useless_match() {
-     let _: i32 = i;
-     let mut _i_mut = i;
++    let i = 10;
 +    let _: i32 = i;
- fn custom_type_match(se: Choice) {
-     let _: Choice = se;
 +    let s = "test";
 +    let _: &str = s;
 +}
 +
-     let _: Choice = match se {
-         Choice::A => Choice::A,
-         Choice::B => Choice::B,
-         _ => Choice::C,
++fn custom_type_match() {
++    let se = Simple::A;
++    let _: Simple = se;
 +    // Don't trigger
-     let _: Choice = match se {
-         Choice::A => Choice::B,
-         Choice::B => Choice::C,
-         Choice::C => Choice::D,
-         Choice::D => Choice::A,
++    let _: Simple = match se {
++        Simple::A => Simple::A,
++        Simple::B => Simple::B,
++        _ => Simple::C,
 +    };
 +    // Mingled, don't trigger
- fn if_let_option() -> Option<i32> {
-     Some(1)
++    let _: Simple = match se {
++        Simple::A => Simple::B,
++        Simple::B => Simple::C,
++        Simple::C => Simple::D,
++        Simple::D => Simple::A,
 +    };
 +}
 +
 +fn option_match(x: Option<i32>) {
 +    let _: Option<i32> = x;
 +    // Don't trigger, this is the case for manual_map_option
 +    let _: Option<i32> = match x {
 +        Some(a) => Some(-a),
 +        None => None,
 +    };
 +}
 +
 +fn func_ret_err<T>(err: T) -> Result<i32, T> {
 +    Err(err)
 +}
 +
 +fn result_match() {
 +    let _: Result<i32, i32> = Ok(1);
 +    let _: Result<i32, i32> = func_ret_err(0_i32);
++    // as ref, don't trigger
++    let res = &func_ret_err(0_i32);
++    let _: Result<&i32, &i32> = match *res {
++        Ok(ref x) => Ok(x),
++        Err(ref x) => Err(x),
++    };
 +}
 +
- fn if_let_result(x: Result<(), i32>) {
-     let _: Result<(), i32> = x;
-     let _: Result<(), i32> = x;
++fn if_let_option() {
++    let _ = Some(1);
++
++    fn do_something() {}
++
++    // Don't trigger
++    let _ = if let Some(a) = Some(1) {
++        Some(a)
++    } else {
++        do_something();
++        None
++    };
++
++    // Don't trigger
++    let _ = if let Some(a) = Some(1) {
++        do_something();
++        Some(a)
++    } else {
++        None
++    };
 +}
 +
-     let _: Result<(), i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
++fn if_let_result() {
++    let x: Result<i32, i32> = Ok(1);
++    let _: Result<i32, i32> = x;
++    let _: Result<i32, i32> = x;
 +    // Input type mismatch, don't trigger
- fn if_let_custom_enum(x: Choice) {
-     let _: Choice = x;
++    let _: Result<i32, i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
 +}
 +
-     let _: Choice = if let Choice::A = x {
-         Choice::A
++fn if_let_custom_enum(x: Simple) {
++    let _: Simple = x;
++
 +    // Don't trigger
-         Choice::B
++    let _: Simple = if let Simple::A = x {
++        Simple::A
 +    } else if true {
++        Simple::B
 +    } else {
 +        x
 +    };
 +}
 +
++mod issue8542 {
++    #[derive(Clone, Copy)]
++    enum E {
++        VariantA(u8, u8),
++        VariantB(u8, bool),
++    }
++
++    enum Complex {
++        A(u8),
++        B(u8, bool),
++        C(u8, i32, f64),
++        D(E, bool),
++    }
++
++    fn match_test() {
++        let ce = Complex::B(8, false);
++        let aa = 0_u8;
++        let bb = false;
++
++        let _: Complex = ce;
++
++        // Don't trigger
++        let _: Complex = match ce {
++            Complex::A(_) => Complex::A(aa),
++            Complex::B(_, b) => Complex::B(aa, b),
++            Complex::C(_, b, _) => Complex::C(aa, b, 64_f64),
++            Complex::D(e, b) => Complex::D(e, b),
++        };
++
++        // Don't trigger
++        let _: Complex = match ce {
++            Complex::A(a) => Complex::A(a),
++            Complex::B(a, _) => Complex::B(a, bb),
++            Complex::C(a, _, _) => Complex::C(a, 32_i32, 64_f64),
++            _ => ce,
++        };
++    }
++}
++
++/// Lint triggered when type coercions happen.
++/// Do NOT trigger on any of these.
++mod issue8551 {
++    trait Trait {}
++    struct Struct;
++    impl Trait for Struct {}
++
++    fn optmap(s: Option<&Struct>) -> Option<&dyn Trait> {
++        match s {
++            Some(s) => Some(s),
++            None => None,
++        }
++    }
++
++    fn lint_tests() {
++        let option: Option<&Struct> = None;
++        let _: Option<&dyn Trait> = match option {
++            Some(s) => Some(s),
++            None => None,
++        };
++
++        let _: Option<&dyn Trait> = if true {
++            match option {
++                Some(s) => Some(s),
++                None => None,
++            }
++        } else {
++            None
++        };
++
++        let result: Result<&Struct, i32> = Err(0);
++        let _: Result<&dyn Trait, i32> = match result {
++            Ok(s) => Ok(s),
++            Err(e) => Err(e),
++        };
++
++        let _: Option<&dyn Trait> = if let Some(s) = option { Some(s) } else { None };
++    }
++}
++
++trait Tr {
++    fn as_mut(&mut self) -> Result<&mut i32, &mut i32>;
++}
++impl Tr for Result<i32, i32> {
++    fn as_mut(&mut self) -> Result<&mut i32, &mut i32> {
++        match self {
++            Ok(x) => Ok(x),
++            Err(e) => Err(e),
++        }
++    }
++}
++
 +fn main() {}
index 36649de35a6030f91a1716c9d23844689981fccf,0000000000000000000000000000000000000000..d210ecff7f1633a8a6e157e643cc9d42725457e9
mode 100644,000000..100644
--- /dev/null
@@@ -1,122 -1,0 +1,234 @@@
- enum Choice {
 +// run-rustfix
 +#![warn(clippy::needless_match)]
 +#![allow(clippy::manual_map)]
 +#![allow(dead_code)]
 +
 +#[derive(Clone, Copy)]
- #[allow(unused_mut)]
++enum Simple {
 +    A,
 +    B,
 +    C,
 +    D,
 +}
 +
-     let mut i = 10;
 +fn useless_match() {
-     let _: i32 = match i {
-         0 => 0,
-         1 => 1,
-         ref i => *i,
-     };
-     let mut _i_mut = match i {
-         0 => 0,
-         1 => 1,
-         ref mut i => *i,
-     };
++    let i = 10;
 +    let _: i32 = match i {
 +        0 => 0,
 +        1 => 1,
 +        2 => 2,
 +        _ => i,
 +    };
- fn custom_type_match(se: Choice) {
-     let _: Choice = match se {
-         Choice::A => Choice::A,
-         Choice::B => Choice::B,
-         Choice::C => Choice::C,
-         Choice::D => Choice::D,
 +    let s = "test";
 +    let _: &str = match s {
 +        "a" => "a",
 +        "b" => "b",
 +        s => s,
 +    };
 +}
 +
-     let _: Choice = match se {
-         Choice::A => Choice::A,
-         Choice::B => Choice::B,
-         _ => Choice::C,
++fn custom_type_match() {
++    let se = Simple::A;
++    let _: Simple = match se {
++        Simple::A => Simple::A,
++        Simple::B => Simple::B,
++        Simple::C => Simple::C,
++        Simple::D => Simple::D,
 +    };
 +    // Don't trigger
-     let _: Choice = match se {
-         Choice::A => Choice::B,
-         Choice::B => Choice::C,
-         Choice::C => Choice::D,
-         Choice::D => Choice::A,
++    let _: Simple = match se {
++        Simple::A => Simple::A,
++        Simple::B => Simple::B,
++        _ => Simple::C,
 +    };
 +    // Mingled, don't trigger
- fn if_let_option() -> Option<i32> {
-     if let Some(a) = Some(1) { Some(a) } else { None }
++    let _: Simple = match se {
++        Simple::A => Simple::B,
++        Simple::B => Simple::C,
++        Simple::C => Simple::D,
++        Simple::D => Simple::A,
 +    };
 +}
 +
 +fn option_match(x: Option<i32>) {
 +    let _: Option<i32> = match x {
 +        Some(a) => Some(a),
 +        None => None,
 +    };
 +    // Don't trigger, this is the case for manual_map_option
 +    let _: Option<i32> = match x {
 +        Some(a) => Some(-a),
 +        None => None,
 +    };
 +}
 +
 +fn func_ret_err<T>(err: T) -> Result<i32, T> {
 +    Err(err)
 +}
 +
 +fn result_match() {
 +    let _: Result<i32, i32> = match Ok(1) {
 +        Ok(a) => Ok(a),
 +        Err(err) => Err(err),
 +    };
 +    let _: Result<i32, i32> = match func_ret_err(0_i32) {
 +        Err(err) => Err(err),
 +        Ok(a) => Ok(a),
 +    };
++    // as ref, don't trigger
++    let res = &func_ret_err(0_i32);
++    let _: Result<&i32, &i32> = match *res {
++        Ok(ref x) => Ok(x),
++        Err(ref x) => Err(x),
++    };
 +}
 +
- fn if_let_result(x: Result<(), i32>) {
-     let _: Result<(), i32> = if let Err(e) = x { Err(e) } else { x };
-     let _: Result<(), i32> = if let Ok(val) = x { Ok(val) } else { x };
++fn if_let_option() {
++    let _ = if let Some(a) = Some(1) { Some(a) } else { None };
++
++    fn do_something() {}
++
++    // Don't trigger
++    let _ = if let Some(a) = Some(1) {
++        Some(a)
++    } else {
++        do_something();
++        None
++    };
++
++    // Don't trigger
++    let _ = if let Some(a) = Some(1) {
++        do_something();
++        Some(a)
++    } else {
++        None
++    };
 +}
 +
-     let _: Result<(), i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
++fn if_let_result() {
++    let x: Result<i32, i32> = Ok(1);
++    let _: Result<i32, i32> = if let Err(e) = x { Err(e) } else { x };
++    let _: Result<i32, i32> = if let Ok(val) = x { Ok(val) } else { x };
 +    // Input type mismatch, don't trigger
- fn if_let_custom_enum(x: Choice) {
-     let _: Choice = if let Choice::A = x {
-         Choice::A
-     } else if let Choice::B = x {
-         Choice::B
-     } else if let Choice::C = x {
-         Choice::C
++    let _: Result<i32, i32> = if let Err(e) = Ok(1) { Err(e) } else { x };
 +}
 +
-     let _: Choice = if let Choice::A = x {
-         Choice::A
++fn if_let_custom_enum(x: Simple) {
++    let _: Simple = if let Simple::A = x {
++        Simple::A
++    } else if let Simple::B = x {
++        Simple::B
++    } else if let Simple::C = x {
++        Simple::C
 +    } else {
 +        x
 +    };
++
 +    // Don't trigger
-         Choice::B
++    let _: Simple = if let Simple::A = x {
++        Simple::A
 +    } else if true {
++        Simple::B
 +    } else {
 +        x
 +    };
 +}
 +
++mod issue8542 {
++    #[derive(Clone, Copy)]
++    enum E {
++        VariantA(u8, u8),
++        VariantB(u8, bool),
++    }
++
++    enum Complex {
++        A(u8),
++        B(u8, bool),
++        C(u8, i32, f64),
++        D(E, bool),
++    }
++
++    fn match_test() {
++        let ce = Complex::B(8, false);
++        let aa = 0_u8;
++        let bb = false;
++
++        let _: Complex = match ce {
++            Complex::A(a) => Complex::A(a),
++            Complex::B(a, b) => Complex::B(a, b),
++            Complex::C(a, b, c) => Complex::C(a, b, c),
++            Complex::D(E::VariantA(ea, eb), b) => Complex::D(E::VariantA(ea, eb), b),
++            Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(ea, eb), b),
++        };
++
++        // Don't trigger
++        let _: Complex = match ce {
++            Complex::A(_) => Complex::A(aa),
++            Complex::B(_, b) => Complex::B(aa, b),
++            Complex::C(_, b, _) => Complex::C(aa, b, 64_f64),
++            Complex::D(e, b) => Complex::D(e, b),
++        };
++
++        // Don't trigger
++        let _: Complex = match ce {
++            Complex::A(a) => Complex::A(a),
++            Complex::B(a, _) => Complex::B(a, bb),
++            Complex::C(a, _, _) => Complex::C(a, 32_i32, 64_f64),
++            _ => ce,
++        };
++    }
++}
++
++/// Lint triggered when type coercions happen.
++/// Do NOT trigger on any of these.
++mod issue8551 {
++    trait Trait {}
++    struct Struct;
++    impl Trait for Struct {}
++
++    fn optmap(s: Option<&Struct>) -> Option<&dyn Trait> {
++        match s {
++            Some(s) => Some(s),
++            None => None,
++        }
++    }
++
++    fn lint_tests() {
++        let option: Option<&Struct> = None;
++        let _: Option<&dyn Trait> = match option {
++            Some(s) => Some(s),
++            None => None,
++        };
++
++        let _: Option<&dyn Trait> = if true {
++            match option {
++                Some(s) => Some(s),
++                None => None,
++            }
++        } else {
++            None
++        };
++
++        let result: Result<&Struct, i32> = Err(0);
++        let _: Result<&dyn Trait, i32> = match result {
++            Ok(s) => Ok(s),
++            Err(e) => Err(e),
++        };
++
++        let _: Option<&dyn Trait> = if let Some(s) = option { Some(s) } else { None };
++    }
++}
++
++trait Tr {
++    fn as_mut(&mut self) -> Result<&mut i32, &mut i32>;
++}
++impl Tr for Result<i32, i32> {
++    fn as_mut(&mut self) -> Result<&mut i32, &mut i32> {
++        match self {
++            Ok(x) => Ok(x),
++            Err(e) => Err(e),
++        }
++    }
++}
++
 +fn main() {}
index ad1525406ade7abd6029b8f85278520b478c768e,0000000000000000000000000000000000000000..34c5226f06057611d9eb87ac5c631b4d241850e8
mode 100644,000000..100644
--- /dev/null
@@@ -1,122 -1,0 +1,113 @@@
-   --> $DIR/needless_match.rs:17:18
 +error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:23:18
-    |
- LL |       let _: i32 = match i {
-    |  __________________^
- LL | |         0 => 0,
- LL | |         1 => 1,
- LL | |         ref i => *i,
- LL | |     };
-    | |_____^ help: replace it with: `i`
- error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:28:22
-    |
- LL |       let mut _i_mut = match i {
-    |  ______________________^
- LL | |         0 => 0,
- LL | |         1 => 1,
- LL | |         ref mut i => *i,
- LL | |     };
-    | |_____^ help: replace it with: `i`
- error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:35:19
++  --> $DIR/needless_match.rs:16:18
 +   |
 +LL |       let _: i32 = match i {
 +   |  __________________^
 +LL | |         0 => 0,
 +LL | |         1 => 1,
 +LL | |         2 => 2,
 +LL | |         _ => i,
 +LL | |     };
 +   | |_____^ help: replace it with: `i`
 +   |
 +   = note: `-D clippy::needless-match` implied by `-D warnings`
 +
 +error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:43:21
++  --> $DIR/needless_match.rs:23:19
 +   |
 +LL |       let _: &str = match s {
 +   |  ___________________^
 +LL | |         "a" => "a",
 +LL | |         "b" => "b",
 +LL | |         s => s,
 +LL | |     };
 +   | |_____^ help: replace it with: `s`
 +
 +error: this match expression is unnecessary
- LL |       let _: Choice = match se {
++  --> $DIR/needless_match.rs:32:21
 +   |
- LL | |         Choice::A => Choice::A,
- LL | |         Choice::B => Choice::B,
- LL | |         Choice::C => Choice::C,
- LL | |         Choice::D => Choice::D,
++LL |       let _: Simple = match se {
 +   |  _____________________^
-   --> $DIR/needless_match.rs:65:26
++LL | |         Simple::A => Simple::A,
++LL | |         Simple::B => Simple::B,
++LL | |         Simple::C => Simple::C,
++LL | |         Simple::D => Simple::D,
 +LL | |     };
 +   | |_____^ help: replace it with: `se`
 +
 +error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:81:31
++  --> $DIR/needless_match.rs:54:26
 +   |
 +LL |       let _: Option<i32> = match x {
 +   |  __________________________^
 +LL | |         Some(a) => Some(a),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: replace it with: `x`
 +
 +error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:85:31
++  --> $DIR/needless_match.rs:70:31
 +   |
 +LL |       let _: Result<i32, i32> = match Ok(1) {
 +   |  _______________________________^
 +LL | |         Ok(a) => Ok(a),
 +LL | |         Err(err) => Err(err),
 +LL | |     };
 +   | |_____^ help: replace it with: `Ok(1)`
 +
 +error: this match expression is unnecessary
-   --> $DIR/needless_match.rs:92:5
++  --> $DIR/needless_match.rs:74:31
 +   |
 +LL |       let _: Result<i32, i32> = match func_ret_err(0_i32) {
 +   |  _______________________________^
 +LL | |         Err(err) => Err(err),
 +LL | |         Ok(a) => Ok(a),
 +LL | |     };
 +   | |_____^ help: replace it with: `func_ret_err(0_i32)`
 +
 +error: this if-let expression is unnecessary
- LL |     if let Some(a) = Some(1) { Some(a) } else { None }
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(1)`
++  --> $DIR/needless_match.rs:87:13
 +   |
-   --> $DIR/needless_match.rs:96:30
++LL |     let _ = if let Some(a) = Some(1) { Some(a) } else { None };
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(1)`
 +
 +error: this if-let expression is unnecessary
- LL |     let _: Result<(), i32> = if let Err(e) = x { Err(e) } else { x };
-    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
++  --> $DIR/needless_match.rs:110:31
 +   |
-   --> $DIR/needless_match.rs:97:30
++LL |     let _: Result<i32, i32> = if let Err(e) = x { Err(e) } else { x };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
 +
 +error: this if-let expression is unnecessary
- LL |     let _: Result<(), i32> = if let Ok(val) = x { Ok(val) } else { x };
-    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
++  --> $DIR/needless_match.rs:111:31
 +   |
-   --> $DIR/needless_match.rs:103:21
++LL |     let _: Result<i32, i32> = if let Ok(val) = x { Ok(val) } else { x };
++   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x`
 +
 +error: this if-let expression is unnecessary
- LL |       let _: Choice = if let Choice::A = x {
++  --> $DIR/needless_match.rs:117:21
 +   |
- LL | |         Choice::A
- LL | |     } else if let Choice::B = x {
- LL | |         Choice::B
++LL |       let _: Simple = if let Simple::A = x {
 +   |  _____________________^
- error: aborting due to 12 previous errors
++LL | |         Simple::A
++LL | |     } else if let Simple::B = x {
++LL | |         Simple::B
 +...  |
 +LL | |         x
 +LL | |     };
 +   | |_____^ help: replace it with: `x`
 +
++error: this match expression is unnecessary
++  --> $DIR/needless_match.rs:156:26
++   |
++LL |           let _: Complex = match ce {
++   |  __________________________^
++LL | |             Complex::A(a) => Complex::A(a),
++LL | |             Complex::B(a, b) => Complex::B(a, b),
++LL | |             Complex::C(a, b, c) => Complex::C(a, b, c),
++LL | |             Complex::D(E::VariantA(ea, eb), b) => Complex::D(E::VariantA(ea, eb), b),
++LL | |             Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(ea, eb), b),
++LL | |         };
++   | |_________^ help: replace it with: `ce`
++
++error: aborting due to 11 previous errors
 +
index d721452ae88803431fd289feb9e223100b16f3ea,0000000000000000000000000000000000000000..c09b07db3dca9787a2c6d585057dcf188e39b508
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,41 @@@
- #[warn(clippy::needless_option_as_deref)]
 +// run-rustfix
 +
++#![allow(unused)]
++#![warn(clippy::needless_option_as_deref)]
 +
 +fn main() {
 +    // should lint
 +    let _: Option<&usize> = Some(&1);
 +    let _: Option<&mut usize> = Some(&mut 1);
 +
++    let mut y = 0;
++    let mut x = Some(&mut y);
++    let _ = x;
++
 +    // should not lint
 +    let _ = Some(Box::new(1)).as_deref();
 +    let _ = Some(Box::new(1)).as_deref_mut();
++
++    // #7846
++    let mut i = 0;
++    let mut opt_vec = vec![Some(&mut i)];
++    opt_vec[0].as_deref_mut().unwrap();
++
++    let mut i = 0;
++    let x = &mut Some(&mut i);
++    (*x).as_deref_mut();
++
++    // #8047
++    let mut y = 0;
++    let mut x = Some(&mut y);
++    x.as_deref_mut();
++    dbg!(x);
++}
++
++struct S<'a> {
++    opt: Option<&'a mut usize>,
++}
++
++fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> {
++    s.opt.as_deref_mut()
 +}
index bb15512adf6aa6c656bba664d822be00aa44364b,0000000000000000000000000000000000000000..c3ba27ecccf22fe8c09ca1327c62944f8b72d75b
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,41 @@@
- #[warn(clippy::needless_option_as_deref)]
 +// run-rustfix
 +
++#![allow(unused)]
++#![warn(clippy::needless_option_as_deref)]
 +
 +fn main() {
 +    // should lint
 +    let _: Option<&usize> = Some(&1).as_deref();
 +    let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
 +
++    let mut y = 0;
++    let mut x = Some(&mut y);
++    let _ = x.as_deref_mut();
++
 +    // should not lint
 +    let _ = Some(Box::new(1)).as_deref();
 +    let _ = Some(Box::new(1)).as_deref_mut();
++
++    // #7846
++    let mut i = 0;
++    let mut opt_vec = vec![Some(&mut i)];
++    opt_vec[0].as_deref_mut().unwrap();
++
++    let mut i = 0;
++    let x = &mut Some(&mut i);
++    (*x).as_deref_mut();
++
++    // #8047
++    let mut y = 0;
++    let mut x = Some(&mut y);
++    x.as_deref_mut();
++    dbg!(x);
++}
++
++struct S<'a> {
++    opt: Option<&'a mut usize>,
++}
++
++fn from_field<'a>(s: &'a mut S<'a>) -> Option<&'a mut usize> {
++    s.opt.as_deref_mut()
 +}
index 5dd507b4a71e8fef8207e5ac6b1b579cac4f9b28,0000000000000000000000000000000000000000..bc07db5b38ed3ffcb1f161dea22ad85445811857
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,22 @@@
-   --> $DIR/needless_option_as_deref.rs:7:29
 +error: derefed type is same as origin
-   --> $DIR/needless_option_as_deref.rs:8:33
++  --> $DIR/needless_option_as_deref.rs:8:29
 +   |
 +LL |     let _: Option<&usize> = Some(&1).as_deref();
 +   |                             ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)`
 +   |
 +   = note: `-D clippy::needless-option-as-deref` implied by `-D warnings`
 +
 +error: derefed type is same as origin
- error: aborting due to 2 previous errors
++  --> $DIR/needless_option_as_deref.rs:9:33
 +   |
 +LL |     let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
 +   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)`
 +
++error: derefed type is same as origin
++  --> $DIR/needless_option_as_deref.rs:13:13
++   |
++LL |     let _ = x.as_deref_mut();
++   |             ^^^^^^^^^^^^^^^^ help: try this: `x`
++
++error: aborting due to 3 previous errors
 +
index 5427c88faf348e3c3399253280b187f7e42599e0,0000000000000000000000000000000000000000..7ece66a1ccb6f9117df23ed1cb99f8ec1a60ecd8
mode 100644,000000..100644
--- /dev/null
@@@ -1,144 -1,0 +1,144 @@@
- struct GreetStruct3 {}
 +#![feature(box_syntax, fn_traits, unboxed_closures)]
 +#![warn(clippy::no_effect_underscore_binding)]
 +#![allow(dead_code)]
 +#![allow(path_statements)]
 +#![allow(clippy::deref_addrof)]
 +#![allow(clippy::redundant_field_names)]
 +#![feature(untagged_unions)]
 +
 +struct Unit;
 +struct Tuple(i32);
 +struct Struct {
 +    field: i32,
 +}
 +enum Enum {
 +    Tuple(i32),
 +    Struct { field: i32 },
 +}
 +struct DropUnit;
 +impl Drop for DropUnit {
 +    fn drop(&mut self) {}
 +}
 +struct DropStruct {
 +    field: i32,
 +}
 +impl Drop for DropStruct {
 +    fn drop(&mut self) {}
 +}
 +struct DropTuple(i32);
 +impl Drop for DropTuple {
 +    fn drop(&mut self) {}
 +}
 +enum DropEnum {
 +    Tuple(i32),
 +    Struct { field: i32 },
 +}
 +impl Drop for DropEnum {
 +    fn drop(&mut self) {}
 +}
 +struct FooString {
 +    s: String,
 +}
 +union Union {
 +    a: u8,
 +    b: f64,
 +}
 +
 +fn get_number() -> i32 {
 +    0
 +}
 +fn get_struct() -> Struct {
 +    Struct { field: 0 }
 +}
 +fn get_drop_struct() -> DropStruct {
 +    DropStruct { field: 0 }
 +}
 +
 +unsafe fn unsafe_fn() -> i32 {
 +    0
 +}
 +
 +struct GreetStruct1;
 +
 +impl FnOnce<(&str,)> for GreetStruct1 {
 +    type Output = ();
 +
 +    extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
 +        println!("hello {}", who);
 +    }
 +}
 +
 +struct GreetStruct2();
 +
 +impl FnOnce<(&str,)> for GreetStruct2 {
 +    type Output = ();
 +
 +    extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
 +        println!("hello {}", who);
 +    }
 +}
 +
++struct GreetStruct3;
 +
 +impl FnOnce<(&str,)> for GreetStruct3 {
 +    type Output = ();
 +
 +    extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
 +        println!("hello {}", who);
 +    }
 +}
 +
 +fn main() {
 +    let s = get_struct();
 +    let s2 = get_struct();
 +
 +    0;
 +    s2;
 +    Unit;
 +    Tuple(0);
 +    Struct { field: 0 };
 +    Struct { ..s };
 +    Union { a: 0 };
 +    Enum::Tuple(0);
 +    Enum::Struct { field: 0 };
 +    5 + 6;
 +    *&42;
 +    &6;
 +    (5, 6, 7);
 +    box 42;
 +    ..;
 +    5..;
 +    ..5;
 +    5..6;
 +    5..=6;
 +    [42, 55];
 +    [42, 55][1];
 +    (42, 55).1;
 +    [42; 55];
 +    [42; 55][13];
 +    let mut x = 0;
 +    || x += 5;
 +    let s: String = "foo".into();
 +    FooString { s: s };
 +    let _unused = 1;
 +    let _penguin = || println!("Some helpful closure");
 +    let _duck = Struct { field: 0 };
 +    let _cat = [2, 4, 6, 8][2];
 +
 +    #[allow(clippy::no_effect)]
 +    0;
 +
 +    // Do not warn
 +    get_number();
 +    unsafe { unsafe_fn() };
 +    let _used = get_struct();
 +    let _x = vec![1];
 +    DropUnit;
 +    DropStruct { field: 0 };
 +    DropTuple(0);
 +    DropEnum::Tuple(0);
 +    DropEnum::Struct { field: 0 };
 +    GreetStruct1("world");
 +    GreetStruct2()("world");
 +    GreetStruct3 {}("world");
 +}
index 7d29445e66c8b97b8730f096f45db5eb3a321255,0000000000000000000000000000000000000000..1290bd8efebd287eda8df11864090b9202a229ba
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,88 @@@
-     if let Some(a) = option() { do_nothing(a) }}
 +// run-rustfix
 +
 +#![warn(clippy::option_map_unit_fn)]
 +#![allow(unused)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +fn do_nothing<T>(_: T) {}
 +
 +fn diverge<T>(_: T) -> ! {
 +    panic!()
 +}
 +
 +fn plus_one(value: usize) -> usize {
 +    value + 1
 +}
 +
 +fn option() -> Option<usize> {
 +    Some(10)
 +}
 +
 +struct HasOption {
 +    field: Option<usize>,
 +}
 +
 +impl HasOption {
 +    fn do_option_nothing(&self, value: usize) {}
 +
 +    fn do_option_plus_one(&self, value: usize) -> usize {
 +        value + 1
 +    }
 +}
 +#[rustfmt::skip]
 +fn option_map_unit_fn() {
 +    let x = HasOption { field: Some(10) };
 +
 +    x.field.map(plus_one);
 +    let _ : Option<()> = x.field.map(do_nothing);
 +
 +    if let Some(x_field) = x.field { do_nothing(x_field) }
 +
 +    if let Some(x_field) = x.field { do_nothing(x_field) }
 +
 +    if let Some(x_field) = x.field { diverge(x_field) }
 +
 +    let captured = 10;
 +    if let Some(value) = x.field { do_nothing(value + captured) };
 +    let _ : Option<()> = x.field.map(|value| do_nothing(value + captured));
 +
 +    if let Some(value) = x.field { x.do_option_nothing(value + captured) }
 +
 +    if let Some(value) = x.field { x.do_option_plus_one(value + captured); }
 +
 +
 +    if let Some(value) = x.field { do_nothing(value + captured) }
 +
 +    if let Some(value) = x.field { do_nothing(value + captured) }
 +
 +    if let Some(value) = x.field { do_nothing(value + captured); }
 +
 +    if let Some(value) = x.field { do_nothing(value + captured); }
 +
 +
 +    if let Some(value) = x.field { diverge(value + captured) }
 +
 +    if let Some(value) = x.field { diverge(value + captured) }
 +
 +    if let Some(value) = x.field { diverge(value + captured); }
 +
 +    if let Some(value) = x.field { diverge(value + captured); }
 +
 +
 +    x.field.map(|value| plus_one(value + captured));
 +    x.field.map(|value| { plus_one(value + captured) });
 +    if let Some(value) = x.field { let y = plus_one(value + captured); }
 +
 +    if let Some(value) = x.field { plus_one(value + captured); }
 +
 +    if let Some(value) = x.field { plus_one(value + captured); }
 +
 +
 +    if let Some(ref value) = x.field { do_nothing(value + captured) }
 +
++    if let Some(a) = option() { do_nothing(a) }
++
++    if let Some(value) = option() { println!("{:?}", value) }
++}
 +
 +fn main() {}
index b6f834f686f9f34cf68ef9f27dc131a226664ee6,0000000000000000000000000000000000000000..f3e5b62c65b7f769bb0812d8460a2791b0a14c65
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,88 @@@
-     option().map(do_nothing);}
 +// run-rustfix
 +
 +#![warn(clippy::option_map_unit_fn)]
 +#![allow(unused)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +fn do_nothing<T>(_: T) {}
 +
 +fn diverge<T>(_: T) -> ! {
 +    panic!()
 +}
 +
 +fn plus_one(value: usize) -> usize {
 +    value + 1
 +}
 +
 +fn option() -> Option<usize> {
 +    Some(10)
 +}
 +
 +struct HasOption {
 +    field: Option<usize>,
 +}
 +
 +impl HasOption {
 +    fn do_option_nothing(&self, value: usize) {}
 +
 +    fn do_option_plus_one(&self, value: usize) -> usize {
 +        value + 1
 +    }
 +}
 +#[rustfmt::skip]
 +fn option_map_unit_fn() {
 +    let x = HasOption { field: Some(10) };
 +
 +    x.field.map(plus_one);
 +    let _ : Option<()> = x.field.map(do_nothing);
 +
 +    x.field.map(do_nothing);
 +
 +    x.field.map(do_nothing);
 +
 +    x.field.map(diverge);
 +
 +    let captured = 10;
 +    if let Some(value) = x.field { do_nothing(value + captured) };
 +    let _ : Option<()> = x.field.map(|value| do_nothing(value + captured));
 +
 +    x.field.map(|value| x.do_option_nothing(value + captured));
 +
 +    x.field.map(|value| { x.do_option_plus_one(value + captured); });
 +
 +
 +    x.field.map(|value| do_nothing(value + captured));
 +
 +    x.field.map(|value| { do_nothing(value + captured) });
 +
 +    x.field.map(|value| { do_nothing(value + captured); });
 +
 +    x.field.map(|value| { { do_nothing(value + captured); } });
 +
 +
 +    x.field.map(|value| diverge(value + captured));
 +
 +    x.field.map(|value| { diverge(value + captured) });
 +
 +    x.field.map(|value| { diverge(value + captured); });
 +
 +    x.field.map(|value| { { diverge(value + captured); } });
 +
 +
 +    x.field.map(|value| plus_one(value + captured));
 +    x.field.map(|value| { plus_one(value + captured) });
 +    x.field.map(|value| { let y = plus_one(value + captured); });
 +
 +    x.field.map(|value| { plus_one(value + captured); });
 +
 +    x.field.map(|value| { { plus_one(value + captured); } });
 +
 +
 +    x.field.map(|ref value| { do_nothing(value + captured) });
 +
++    option().map(do_nothing);
++
++    option().map(|value| println!("{:?}", value));
++}
 +
 +fn main() {}
index 8abdbcafb6e935ed9ae422fc893e801f27363723,0000000000000000000000000000000000000000..ab2a294a060f0c2507b81f1eedd6288e4b486f3d
mode 100644,000000..100644
--- /dev/null
@@@ -1,148 -1,0 +1,156 @@@
- LL |     option().map(do_nothing);}
 +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:39:5
 +   |
 +LL |     x.field.map(do_nothing);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
 +   |
 +   = note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
 +
 +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:41:5
 +   |
 +LL |     x.field.map(do_nothing);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:43:5
 +   |
 +LL |     x.field.map(diverge);
 +   |     ^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:49:5
 +   |
 +LL |     x.field.map(|value| x.do_option_nothing(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:51:5
 +   |
 +LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:54:5
 +   |
 +LL |     x.field.map(|value| do_nothing(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:56:5
 +   |
 +LL |     x.field.map(|value| { do_nothing(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:58:5
 +   |
 +LL |     x.field.map(|value| { do_nothing(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:60:5
 +   |
 +LL |     x.field.map(|value| { { do_nothing(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:63:5
 +   |
 +LL |     x.field.map(|value| diverge(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:65:5
 +   |
 +LL |     x.field.map(|value| { diverge(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:67:5
 +   |
 +LL |     x.field.map(|value| { diverge(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:69:5
 +   |
 +LL |     x.field.map(|value| { { diverge(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:74:5
 +   |
 +LL |     x.field.map(|value| { let y = plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:76:5
 +   |
 +LL |     x.field.map(|value| { plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:78:5
 +   |
 +LL |     x.field.map(|value| { { plus_one(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:81:5
 +   |
 +LL |     x.field.map(|ref value| { do_nothing(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/option_map_unit_fn_fixable.rs:83:5
 +   |
- error: aborting due to 18 previous errors
++LL |     option().map(do_nothing);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Some(a) = option() { do_nothing(a) }`
 +
++error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
++  --> $DIR/option_map_unit_fn_fixable.rs:85:5
++   |
++LL |     option().map(|value| println!("{:?}", value));
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
++   |     |
++   |     help: try this: `if let Some(value) = option() { println!("{:?}", value) }`
++
++error: aborting due to 19 previous errors
 +
index 27d4b795a5eeb8fd31307b952f03006c23068784,0000000000000000000000000000000000000000..6e0d5a87f6807b012fcc55428b5b0aee61882301
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,52 @@@
- struct SomeStruct {}
 +// run-rustfix
 +
 +#![warn(clippy::or_then_unwrap)]
 +#![allow(clippy::map_identity)]
 +
- struct SomeOtherStruct {}
++struct SomeStruct;
 +impl SomeStruct {
 +    fn or(self, _: Option<Self>) -> Self {
 +        self
 +    }
 +    fn unwrap(&self) {}
 +}
 +
++struct SomeOtherStruct;
 +impl SomeOtherStruct {
 +    fn or(self) -> Self {
 +        self
 +    }
 +    fn unwrap(&self) {}
 +}
 +
 +fn main() {
 +    let option: Option<&str> = None;
 +    let _ = option.unwrap_or("fallback"); // should trigger lint
 +
 +    let result: Result<&str, &str> = Err("Error");
 +    let _ = result.unwrap_or("fallback"); // should trigger lint
 +
 +    // as part of a method chain
 +    let option: Option<&str> = None;
 +    let _ = option.map(|v| v).unwrap_or("fallback").to_string().chars(); // should trigger lint
 +
 +    // Not Option/Result
 +    let instance = SomeStruct {};
 +    let _ = instance.or(Some(SomeStruct {})).unwrap(); // should not trigger lint
 +
 +    // or takes no argument
 +    let instance = SomeOtherStruct {};
 +    let _ = instance.or().unwrap(); // should not trigger lint and should not panic
 +
 +    // None in or
 +    let option: Option<&str> = None;
 +    let _ = option.or(None).unwrap(); // should not trigger lint
 +
 +    // Not Err in or
 +    let result: Result<&str, &str> = Err("Error");
 +    let _ = result.or::<&str>(Err("Other Error")).unwrap(); // should not trigger lint
 +
 +    // other function between
 +    let option: Option<&str> = None;
 +    let _ = option.or(Some("fallback")).map(|v| v).unwrap(); // should not trigger lint
 +}
index 0dab5ae2f1c04167c996b5e82e9975a27efe615c,0000000000000000000000000000000000000000..e406a71d46d00d377024971cee471851e0c3a063
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,52 @@@
- struct SomeStruct {}
 +// run-rustfix
 +
 +#![warn(clippy::or_then_unwrap)]
 +#![allow(clippy::map_identity)]
 +
- struct SomeOtherStruct {}
++struct SomeStruct;
 +impl SomeStruct {
 +    fn or(self, _: Option<Self>) -> Self {
 +        self
 +    }
 +    fn unwrap(&self) {}
 +}
 +
++struct SomeOtherStruct;
 +impl SomeOtherStruct {
 +    fn or(self) -> Self {
 +        self
 +    }
 +    fn unwrap(&self) {}
 +}
 +
 +fn main() {
 +    let option: Option<&str> = None;
 +    let _ = option.or(Some("fallback")).unwrap(); // should trigger lint
 +
 +    let result: Result<&str, &str> = Err("Error");
 +    let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint
 +
 +    // as part of a method chain
 +    let option: Option<&str> = None;
 +    let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint
 +
 +    // Not Option/Result
 +    let instance = SomeStruct {};
 +    let _ = instance.or(Some(SomeStruct {})).unwrap(); // should not trigger lint
 +
 +    // or takes no argument
 +    let instance = SomeOtherStruct {};
 +    let _ = instance.or().unwrap(); // should not trigger lint and should not panic
 +
 +    // None in or
 +    let option: Option<&str> = None;
 +    let _ = option.or(None).unwrap(); // should not trigger lint
 +
 +    // Not Err in or
 +    let result: Result<&str, &str> = Err("Error");
 +    let _ = result.or::<&str>(Err("Other Error")).unwrap(); // should not trigger lint
 +
 +    // other function between
 +    let option: Option<&str> = None;
 +    let _ = option.or(Some("fallback")).map(|v| v).unwrap(); // should not trigger lint
 +}
index 7338064646244ca7611a01d73c61203a15a0631f,0000000000000000000000000000000000000000..12a0c776ae2fd6feb90371be57be32ddd59379de
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,95 @@@
- #![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)]
 +#![allow(clippy::assertions_on_constants, clippy::eq_op)]
++#![feature(inline_const)]
++#![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)]
 +
 +extern crate core;
 +
++const _: () = {
++    if 1 == 0 {
++        panic!("A balanced diet means a cupcake in each hand");
++    }
++};
++
++fn inline_const() {
++    let _ = const {
++        if 1 == 0 {
++            panic!("When nothing goes right, go left")
++        }
++    };
++}
++
 +fn panic() {
 +    let a = 2;
 +    panic!();
 +    panic!("message");
 +    panic!("{} {}", "panic with", "multiple arguments");
 +    let b = a + 2;
 +}
 +
 +fn todo() {
 +    let a = 2;
 +    todo!();
 +    todo!("message");
 +    todo!("{} {}", "panic with", "multiple arguments");
 +    let b = a + 2;
 +}
 +
 +fn unimplemented() {
 +    let a = 2;
 +    unimplemented!();
 +    unimplemented!("message");
 +    unimplemented!("{} {}", "panic with", "multiple arguments");
 +    let b = a + 2;
 +}
 +
 +fn unreachable() {
 +    let a = 2;
 +    unreachable!();
 +    unreachable!("message");
 +    unreachable!("{} {}", "panic with", "multiple arguments");
 +    let b = a + 2;
 +}
 +
 +fn core_versions() {
 +    use core::{panic, todo, unimplemented, unreachable};
 +    panic!();
 +    todo!();
 +    unimplemented!();
 +    unreachable!();
 +}
 +
 +fn assert() {
 +    assert!(true);
 +    assert_eq!(true, true);
 +    assert_ne!(true, false);
 +}
 +
 +fn assert_msg() {
 +    assert!(true, "this should not panic");
 +    assert_eq!(true, true, "this should not panic");
 +    assert_ne!(true, false, "this should not panic");
 +}
 +
 +fn debug_assert() {
 +    debug_assert!(true);
 +    debug_assert_eq!(true, true);
 +    debug_assert_ne!(true, false);
 +}
 +
 +fn debug_assert_msg() {
 +    debug_assert!(true, "test");
 +    debug_assert_eq!(true, true, "test");
 +    debug_assert_ne!(true, false, "test");
 +}
 +
 +fn main() {
 +    panic();
 +    todo();
 +    unimplemented();
 +    unreachable();
 +    core_versions();
 +    assert();
 +    assert_msg();
 +    debug_assert();
 +    debug_assert_msg();
 +}
index bfd1c7a380149b2cb89f6480f96b6ed1d1669808,0000000000000000000000000000000000000000..4ceb6d1440f61c58d718ae051124d8e7c12285c4
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,106 @@@
-   --> $DIR/panicking_macros.rs:8:5
 +error: `panic` should not be present in production code
-   --> $DIR/panicking_macros.rs:9:5
++  --> $DIR/panicking_macros.rs:23:5
 +   |
 +LL |     panic!();
 +   |     ^^^^^^^^
 +   |
 +   = note: `-D clippy::panic` implied by `-D warnings`
 +
 +error: `panic` should not be present in production code
-   --> $DIR/panicking_macros.rs:10:5
++  --> $DIR/panicking_macros.rs:24:5
 +   |
 +LL |     panic!("message");
 +   |     ^^^^^^^^^^^^^^^^^
 +
 +error: `panic` should not be present in production code
-   --> $DIR/panicking_macros.rs:16:5
++  --> $DIR/panicking_macros.rs:25:5
 +   |
 +LL |     panic!("{} {}", "panic with", "multiple arguments");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: `todo` should not be present in production code
-   --> $DIR/panicking_macros.rs:17:5
++  --> $DIR/panicking_macros.rs:31:5
 +   |
 +LL |     todo!();
 +   |     ^^^^^^^
 +   |
 +   = note: `-D clippy::todo` implied by `-D warnings`
 +
 +error: `todo` should not be present in production code
-   --> $DIR/panicking_macros.rs:18:5
++  --> $DIR/panicking_macros.rs:32:5
 +   |
 +LL |     todo!("message");
 +   |     ^^^^^^^^^^^^^^^^
 +
 +error: `todo` should not be present in production code
-   --> $DIR/panicking_macros.rs:24:5
++  --> $DIR/panicking_macros.rs:33:5
 +   |
 +LL |     todo!("{} {}", "panic with", "multiple arguments");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: `unimplemented` should not be present in production code
-   --> $DIR/panicking_macros.rs:25:5
++  --> $DIR/panicking_macros.rs:39:5
 +   |
 +LL |     unimplemented!();
 +   |     ^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::unimplemented` implied by `-D warnings`
 +
 +error: `unimplemented` should not be present in production code
-   --> $DIR/panicking_macros.rs:26:5
++  --> $DIR/panicking_macros.rs:40:5
 +   |
 +LL |     unimplemented!("message");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: `unimplemented` should not be present in production code
-   --> $DIR/panicking_macros.rs:32:5
++  --> $DIR/panicking_macros.rs:41:5
 +   |
 +LL |     unimplemented!("{} {}", "panic with", "multiple arguments");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: usage of the `unreachable!` macro
-   --> $DIR/panicking_macros.rs:33:5
++  --> $DIR/panicking_macros.rs:47:5
 +   |
 +LL |     unreachable!();
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::unreachable` implied by `-D warnings`
 +
 +error: usage of the `unreachable!` macro
-   --> $DIR/panicking_macros.rs:34:5
++  --> $DIR/panicking_macros.rs:48:5
 +   |
 +LL |     unreachable!("message");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: usage of the `unreachable!` macro
-   --> $DIR/panicking_macros.rs:40:5
++  --> $DIR/panicking_macros.rs:49:5
 +   |
 +LL |     unreachable!("{} {}", "panic with", "multiple arguments");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: `panic` should not be present in production code
-   --> $DIR/panicking_macros.rs:41:5
++  --> $DIR/panicking_macros.rs:55:5
 +   |
 +LL |     panic!();
 +   |     ^^^^^^^^
 +
 +error: `todo` should not be present in production code
-   --> $DIR/panicking_macros.rs:42:5
++  --> $DIR/panicking_macros.rs:56:5
 +   |
 +LL |     todo!();
 +   |     ^^^^^^^
 +
 +error: `unimplemented` should not be present in production code
-   --> $DIR/panicking_macros.rs:43:5
++  --> $DIR/panicking_macros.rs:57:5
 +   |
 +LL |     unimplemented!();
 +   |     ^^^^^^^^^^^^^^^^
 +
 +error: usage of the `unreachable!` macro
++  --> $DIR/panicking_macros.rs:58:5
 +   |
 +LL |     unreachable!();
 +   |     ^^^^^^^^^^^^^^
 +
 +error: aborting due to 16 previous errors
 +
index 03dd938a2339e57cda8eca5088c8b06a3c5d03ab,0000000000000000000000000000000000000000..814bbc7af713b77783dbcc741888ed95868ad2f9
mode 100644,000000..100644
--- /dev/null
@@@ -1,203 -1,0 +1,203 @@@
-     struct S {}
 +#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
 +#![warn(clippy::ptr_arg)]
 +
 +use std::borrow::Cow;
 +use std::path::PathBuf;
 +
 +fn do_vec(x: &Vec<i64>) {
 +    //Nothing here
 +}
 +
 +fn do_vec_mut(x: &mut Vec<i64>) {
 +    //Nothing here
 +}
 +
 +fn do_str(x: &String) {
 +    //Nothing here either
 +}
 +
 +fn do_str_mut(x: &mut String) {
 +    //Nothing here either
 +}
 +
 +fn do_path(x: &PathBuf) {
 +    //Nothing here either
 +}
 +
 +fn do_path_mut(x: &mut PathBuf) {
 +    //Nothing here either
 +}
 +
 +fn main() {}
 +
 +trait Foo {
 +    type Item;
 +    fn do_vec(x: &Vec<i64>);
 +    fn do_item(x: &Self::Item);
 +}
 +
 +struct Bar;
 +
 +// no error, in trait impl (#425)
 +impl Foo for Bar {
 +    type Item = Vec<u8>;
 +    fn do_vec(x: &Vec<i64>) {}
 +    fn do_item(x: &Vec<u8>) {}
 +}
 +
 +fn cloned(x: &Vec<u8>) -> Vec<u8> {
 +    let e = x.clone();
 +    let f = e.clone(); // OK
 +    let g = x;
 +    let h = g.clone();
 +    let i = (e).clone();
 +    x.clone()
 +}
 +
 +fn str_cloned(x: &String) -> String {
 +    let a = x.clone();
 +    let b = x.clone();
 +    let c = b.clone();
 +    let d = a.clone().clone().clone();
 +    x.clone()
 +}
 +
 +fn path_cloned(x: &PathBuf) -> PathBuf {
 +    let a = x.clone();
 +    let b = x.clone();
 +    let c = b.clone();
 +    let d = a.clone().clone().clone();
 +    x.clone()
 +}
 +
 +fn false_positive_capacity(x: &Vec<u8>, y: &String) {
 +    let a = x.capacity();
 +    let b = y.clone();
 +    let c = y.as_str();
 +}
 +
 +fn false_positive_capacity_too(x: &String) -> String {
 +    if x.capacity() > 1024 {
 +        panic!("Too large!");
 +    }
 +    x.clone()
 +}
 +
 +#[allow(dead_code)]
 +fn test_cow_with_ref(c: &Cow<[i32]>) {}
 +
 +fn test_cow(c: Cow<[i32]>) {
 +    let _c = c;
 +}
 +
 +trait Foo2 {
 +    fn do_string(&self);
 +}
 +
 +// no error for &self references where self is of type String (#2293)
 +impl Foo2 for String {
 +    fn do_string(&self) {}
 +}
 +
 +// Check that the allow attribute on parameters is honored
 +mod issue_5644 {
 +    use std::borrow::Cow;
 +    use std::path::PathBuf;
 +
 +    fn allowed(
 +        #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +        #[allow(clippy::ptr_arg)] _s: &String,
 +        #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +        #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +    ) {
 +    }
 +
++    struct S;
 +    impl S {
 +        fn allowed(
 +            #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +            #[allow(clippy::ptr_arg)] _s: &String,
 +            #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +            #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +        ) {
 +        }
 +    }
 +
 +    trait T {
 +        fn allowed(
 +            #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +            #[allow(clippy::ptr_arg)] _s: &String,
 +            #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +            #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +        ) {
 +        }
 +    }
 +}
 +
 +mod issue6509 {
 +    use std::path::PathBuf;
 +
 +    fn foo_vec(vec: &Vec<u8>) {
 +        let _ = vec.clone().pop();
 +        let _ = vec.clone().clone();
 +    }
 +
 +    fn foo_path(path: &PathBuf) {
 +        let _ = path.clone().pop();
 +        let _ = path.clone().clone();
 +    }
 +
 +    fn foo_str(str: &PathBuf) {
 +        let _ = str.clone().pop();
 +        let _ = str.clone().clone();
 +    }
 +}
 +
 +fn mut_vec_slice_methods(v: &mut Vec<u32>) {
 +    v.copy_within(1..5, 10);
 +}
 +
 +fn mut_vec_vec_methods(v: &mut Vec<u32>) {
 +    v.clear();
 +}
 +
 +fn vec_contains(v: &Vec<u32>) -> bool {
 +    [vec![], vec![0]].as_slice().contains(v)
 +}
 +
 +fn fn_requires_vec(v: &Vec<u32>) -> bool {
 +    vec_contains(v)
 +}
 +
 +fn impl_fn_requires_vec(v: &Vec<u32>, f: impl Fn(&Vec<u32>)) {
 +    f(v);
 +}
 +
 +fn dyn_fn_requires_vec(v: &Vec<u32>, f: &dyn Fn(&Vec<u32>)) {
 +    f(v);
 +}
 +
 +// No error for types behind an alias (#7699)
 +type A = Vec<u8>;
 +fn aliased(a: &A) {}
 +
 +// Issue #8366
 +pub trait Trait {
 +    fn f(v: &mut Vec<i32>);
 +    fn f2(v: &mut Vec<i32>) {}
 +}
 +
 +// Issue #8463
 +fn two_vecs(a: &mut Vec<u32>, b: &mut Vec<u32>) {
 +    a.push(0);
 +    a.push(0);
 +    a.push(0);
 +    b.push(1);
 +}
 +
 +// Issue #8495
 +fn cow_conditional_to_mut(a: &mut Cow<str>) {
 +    if a.is_empty() {
 +        a.to_mut().push_str("foo");
 +    }
 +}
index 9241bf7ed74025b8508ace83be7a2819fe66d09e,0000000000000000000000000000000000000000..f72fc77ab9977dda9e161eb1714b2f912647ca88
mode 100644,000000..100644
--- /dev/null
@@@ -1,321 -1,0 +1,321 @@@
- struct G {}
 +#![warn(clippy::recursive_format_impl)]
 +#![allow(
 +    clippy::inherent_to_string_shadow_display,
 +    clippy::to_string_in_format_args,
 +    clippy::deref_addrof
 +)]
 +
 +use std::fmt;
 +
 +struct A;
 +impl A {
 +    fn fmt(&self) {
 +        self.to_string();
 +    }
 +}
 +
 +trait B {
 +    fn fmt(&self) {}
 +}
 +
 +impl B for A {
 +    fn fmt(&self) {
 +        self.to_string();
 +    }
 +}
 +
 +impl fmt::Display for A {
 +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 +        write!(f, "{}", self.to_string())
 +    }
 +}
 +
 +fn fmt(a: A) {
 +    a.to_string();
 +}
 +
 +struct C;
 +
 +impl C {
 +    // Doesn't trigger if to_string defined separately
 +    // i.e. not using ToString trait (from Display)
 +    fn to_string(&self) -> String {
 +        String::from("I am C")
 +    }
 +}
 +
 +impl fmt::Display for C {
 +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 +        write!(f, "{}", self.to_string())
 +    }
 +}
 +
 +enum D {
 +    E(String),
 +    F,
 +}
 +
 +impl std::fmt::Display for D {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        match &self {
 +            Self::E(string) => write!(f, "E {}", string.to_string()),
 +            Self::F => write!(f, "F"),
 +        }
 +    }
 +}
 +
 +// Check for use of self as Display, in Display impl
 +// Triggers on direct use of self
- struct H {}
++struct G;
 +
 +impl std::fmt::Display for G {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{}", self)
 +    }
 +}
 +
 +// Triggers on reference to self
- struct H2 {}
++struct H;
 +
 +impl std::fmt::Display for H {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{}", &self)
 +    }
 +}
 +
 +impl std::fmt::Debug for H {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{:?}", &self)
 +    }
 +}
 +
 +// Triggers on multiple reference to self
- struct I {}
++struct H2;
 +
 +impl std::fmt::Display for H2 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{}", &&&self)
 +    }
 +}
 +
 +// Doesn't trigger on correct deref
- struct I2 {}
++struct I;
 +
 +impl std::ops::Deref for I {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for I {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", &**self)
 +    }
 +}
 +
 +impl std::fmt::Debug for I {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{:?}", &**self)
 +    }
 +}
 +
 +// Doesn't trigger on multiple correct deref
- struct I3 {}
++struct I2;
 +
 +impl std::ops::Deref for I2 {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for I2 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", **&&&**self)
 +    }
 +}
 +
 +// Doesn't trigger on multiple correct deref
- struct J {}
++struct I3;
 +
 +impl std::ops::Deref for I3 {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for I3 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", &&**&&&**self)
 +    }
 +}
 +
 +// Does trigger when deref resolves to self
- struct J2 {}
++struct J;
 +
 +impl std::ops::Deref for J {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for J {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", &*self)
 +    }
 +}
 +
 +impl std::fmt::Debug for J {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{:?}", &*self)
 +    }
 +}
 +
- struct J3 {}
++struct J2;
 +
 +impl std::ops::Deref for J2 {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for J2 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", *self)
 +    }
 +}
 +
- struct J4 {}
++struct J3;
 +
 +impl std::ops::Deref for J3 {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for J3 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", **&&*self)
 +    }
 +}
 +
- struct K {}
++struct J4;
 +
 +impl std::ops::Deref for J4 {
 +    type Target = str;
 +
 +    fn deref(&self) -> &Self::Target {
 +        "test"
 +    }
 +}
 +
 +impl std::fmt::Display for J4 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", &&**&&*self)
 +    }
 +}
 +
 +// Doesn't trigger on Debug from Display
- struct K2 {}
++struct K;
 +
 +impl std::fmt::Debug for K {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "test")
 +    }
 +}
 +
 +impl std::fmt::Display for K {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{:?}", self)
 +    }
 +}
 +
 +// Doesn't trigger on Display from Debug
++struct K2;
 +
 +impl std::fmt::Debug for K2 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{}", self)
 +    }
 +}
 +
 +impl std::fmt::Display for K2 {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "test")
 +    }
 +}
 +
 +// Doesn't trigger on struct fields
 +struct L {
 +    field1: u32,
 +    field2: i32,
 +}
 +
 +impl std::fmt::Display for L {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{},{}", self.field1, self.field2)
 +    }
 +}
 +
 +impl std::fmt::Debug for L {
 +    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 +        write!(f, "{:?},{:?}", self.field1, self.field2)
 +    }
 +}
 +
 +// Doesn't trigger on nested enum matching
 +enum Tree {
 +    Leaf,
 +    Node(Vec<Tree>),
 +}
 +
 +impl std::fmt::Display for Tree {
 +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 +        match self {
 +            Tree::Leaf => write!(f, "*"),
 +            Tree::Node(children) => {
 +                write!(f, "(")?;
 +                for child in children.iter() {
 +                    write!(f, "{},", child)?;
 +                }
 +                write!(f, ")")
 +            },
 +        }
 +    }
 +}
 +
 +impl std::fmt::Debug for Tree {
 +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 +        match self {
 +            Tree::Leaf => write!(f, "*"),
 +            Tree::Node(children) => {
 +                write!(f, "(")?;
 +                for child in children.iter() {
 +                    write!(f, "{:?},", child)?;
 +                }
 +                write!(f, ")")
 +            },
 +        }
 +    }
 +}
 +
 +fn main() {
 +    let a = A;
 +    a.to_string();
 +    a.fmt();
 +    fmt(a);
 +
 +    let c = C;
 +    c.to_string();
 +}
index 52fbc91e325555a9c808f57a47e76cc48e893363,0000000000000000000000000000000000000000..80f94e5f3cbbb278e4d333f7b1887ff3d51ec81e
mode 100644,000000..100644
--- /dev/null
@@@ -1,100 -1,0 +1,100 @@@
- pub struct MyStruct {}
 +#![warn(clippy::all)]
 +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
 +#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
 +#![allow(unused_imports)]
 +
++pub struct MyStruct;
 +
 +pub struct SubT<T> {
 +    foo: T,
 +}
 +
 +pub enum MyEnum {
 +    One,
 +    Two,
 +}
 +
 +mod outer_box {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn box_test6<T>(foo: Box<Rc<T>>) {}
 +
 +    pub fn box_test7<T>(foo: Box<Arc<T>>) {}
 +
 +    pub fn box_test8() -> Box<Rc<SubT<usize>>> {
 +        unimplemented!();
 +    }
 +
 +    pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
 +        unimplemented!();
 +    }
 +}
 +
 +mod outer_rc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn rc_test5(a: Rc<Box<bool>>) {}
 +
 +    pub fn rc_test7(a: Rc<Arc<bool>>) {}
 +
 +    pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
 +        unimplemented!();
 +    }
 +
 +    pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
 +        unimplemented!();
 +    }
 +}
 +
 +mod outer_arc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn arc_test5(a: Arc<Box<bool>>) {}
 +
 +    pub fn arc_test6(a: Arc<Rc<bool>>) {}
 +
 +    pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
 +        unimplemented!();
 +    }
 +
 +    pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
 +        unimplemented!();
 +    }
 +}
 +
 +// https://github.com/rust-lang/rust-clippy/issues/7487
 +mod box_dyn {
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub trait T {}
 +
 +    struct S {
 +        a: Box<Box<dyn T>>,
 +        b: Rc<Box<dyn T>>,
 +        c: Arc<Box<dyn T>>,
 +    }
 +
 +    pub fn test_box(_: Box<Box<dyn T>>) {}
 +    pub fn test_rc(_: Rc<Box<dyn T>>) {}
 +    pub fn test_arc(_: Arc<Box<dyn T>>) {}
 +    pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
 +}
 +
 +fn main() {}
index ef089b25f47fdae22b8d18c322320fd1cd6f7200,0000000000000000000000000000000000000000..e7ed84731c02e4d64ec6e45cd5782d0e632b2416
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
- pub struct MyStruct {}
 +// run-rustfix
 +#![warn(clippy::all)]
 +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
 +#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
 +#![allow(unused_imports)]
 +
++pub struct MyStruct;
 +
 +pub struct SubT<T> {
 +    foo: T,
 +}
 +
 +pub enum MyEnum {
 +    One,
 +    Two,
 +}
 +
 +mod outer_box {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn box_test1<T>(foo: &T) {}
 +
 +    pub fn box_test2(foo: &MyStruct) {}
 +
 +    pub fn box_test3(foo: &MyEnum) {}
 +
 +    pub fn box_test4_neg(foo: Box<SubT<&usize>>) {}
 +
 +    pub fn box_test5<T>(foo: Box<T>) {}
 +}
 +
 +mod outer_rc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn rc_test1<T>(foo: &T) {}
 +
 +    pub fn rc_test2(foo: &MyStruct) {}
 +
 +    pub fn rc_test3(foo: &MyEnum) {}
 +
 +    pub fn rc_test4_neg(foo: Rc<SubT<&usize>>) {}
 +
 +    pub fn rc_test6(a: Rc<bool>) {}
 +}
 +
 +mod outer_arc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn arc_test1<T>(foo: &T) {}
 +
 +    pub fn arc_test2(foo: &MyStruct) {}
 +
 +    pub fn arc_test3(foo: &MyEnum) {}
 +
 +    pub fn arc_test4_neg(foo: Arc<SubT<&usize>>) {}
 +
 +    pub fn arc_test7(a: Arc<bool>) {}
 +}
 +
 +fn main() {}
index fefa87721d720b9deeb77fe4d27657abb5783b88,0000000000000000000000000000000000000000..de763f98b5c89fb55d344bff8b836fde26f2f916
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
- pub struct MyStruct {}
 +// run-rustfix
 +#![warn(clippy::all)]
 +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
 +#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
 +#![allow(unused_imports)]
 +
++pub struct MyStruct;
 +
 +pub struct SubT<T> {
 +    foo: T,
 +}
 +
 +pub enum MyEnum {
 +    One,
 +    Two,
 +}
 +
 +mod outer_box {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn box_test1<T>(foo: Box<&T>) {}
 +
 +    pub fn box_test2(foo: Box<&MyStruct>) {}
 +
 +    pub fn box_test3(foo: Box<&MyEnum>) {}
 +
 +    pub fn box_test4_neg(foo: Box<SubT<&usize>>) {}
 +
 +    pub fn box_test5<T>(foo: Box<Box<T>>) {}
 +}
 +
 +mod outer_rc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn rc_test1<T>(foo: Rc<&T>) {}
 +
 +    pub fn rc_test2(foo: Rc<&MyStruct>) {}
 +
 +    pub fn rc_test3(foo: Rc<&MyEnum>) {}
 +
 +    pub fn rc_test4_neg(foo: Rc<SubT<&usize>>) {}
 +
 +    pub fn rc_test6(a: Rc<Rc<bool>>) {}
 +}
 +
 +mod outer_arc {
 +    use crate::MyEnum;
 +    use crate::MyStruct;
 +    use crate::SubT;
 +    use std::boxed::Box;
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    pub fn arc_test1<T>(foo: Arc<&T>) {}
 +
 +    pub fn arc_test2(foo: Arc<&MyStruct>) {}
 +
 +    pub fn arc_test3(foo: Arc<&MyEnum>) {}
 +
 +    pub fn arc_test4_neg(foo: Arc<SubT<&usize>>) {}
 +
 +    pub fn arc_test7(a: Arc<Arc<bool>>) {}
 +}
 +
 +fn main() {}
index 16b40dcd902869d7184cb1d6b384139166d04380,0000000000000000000000000000000000000000..1525f6a93dfdd4dcac0492dad3adbf63e8f621f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,236 -1,0 +1,236 @@@
- #![allow(clippy::implicit_clone)]
 +// run-rustfix
 +// rustfix-only-machine-applicable
 +
++#![allow(clippy::implicit_clone, clippy::drop_non_drop)]
 +use std::ffi::OsString;
 +use std::path::Path;
 +
 +fn main() {
 +    let _s = ["lorem", "ipsum"].join(" ");
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let _s = Path::new("/a/b/").join("c");
 +
 +    let _s = Path::new("/a/b/").join("c");
 +
 +    let _s = OsString::new();
 +
 +    let _s = OsString::new();
 +
 +    // Check that lint level works
 +    #[allow(clippy::redundant_clone)]
 +    let _s = String::new().to_string();
 +
 +    let tup = (String::from("foo"),);
 +    let _t = tup.0;
 +
 +    let tup_ref = &(String::from("foo"),);
 +    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
 +
 +    {
 +        let x = String::new();
 +        let y = &x;
 +
 +        let _x = x.clone(); // ok; `x` is borrowed by `y`
 +
 +        let _ = y.len();
 +    }
 +
 +    let x = (String::new(),);
 +    let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x`
 +
 +    with_branch(Alpha, true);
 +    cannot_double_move(Alpha);
 +    cannot_move_from_type_with_drop();
 +    borrower_propagation();
 +    not_consumed();
 +    issue_5405();
 +    manually_drop();
 +    clone_then_move_cloned();
 +    hashmap_neg();
 +    false_negative_5707();
 +}
 +
 +#[derive(Clone)]
 +struct Alpha;
 +fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
 +    if b { (a.clone(), a) } else { (Alpha, a) }
 +}
 +
 +fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) {
 +    (a.clone(), a)
 +}
 +
 +struct TypeWithDrop {
 +    x: String,
 +}
 +
 +impl Drop for TypeWithDrop {
 +    fn drop(&mut self) {}
 +}
 +
 +fn cannot_move_from_type_with_drop() -> String {
 +    let s = TypeWithDrop { x: String::new() };
 +    s.x.clone() // removing this `clone()` summons E0509
 +}
 +
 +fn borrower_propagation() {
 +    let s = String::new();
 +    let t = String::new();
 +
 +    {
 +        fn b() -> bool {
 +            unimplemented!()
 +        }
 +        let _u = if b() { &s } else { &t };
 +
 +        // ok; `s` and `t` are possibly borrowed
 +        let _s = s.clone();
 +        let _t = t.clone();
 +    }
 +
 +    {
 +        let _u = || s.len();
 +        let _v = [&t; 32];
 +        let _s = s.clone(); // ok
 +        let _t = t.clone(); // ok
 +    }
 +
 +    {
 +        let _u = {
 +            let u = Some(&s);
 +            let _ = s.clone(); // ok
 +            u
 +        };
 +        let _s = s.clone(); // ok
 +    }
 +
 +    {
 +        use std::convert::identity as id;
 +        let _u = id(id(&s));
 +        let _s = s.clone(); // ok, `u` borrows `s`
 +    }
 +
 +    let _s = s;
 +    let _t = t;
 +
 +    #[derive(Clone)]
 +    struct Foo {
 +        x: usize,
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = Some(f.x);
 +        let _f = f;
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = &f.x;
 +        let _f = f.clone(); // ok
 +    }
 +}
 +
 +fn not_consumed() {
 +    let x = std::path::PathBuf::from("home");
 +    let y = x.join("matthias");
 +    // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is
 +    // redundant. (It also does not consume the PathBuf)
 +
 +    println!("x: {:?}, y: {:?}", x, y);
 +
 +    let mut s = String::new();
 +    s.clone().push_str("foo"); // OK, removing this `clone()` will change the behavior.
 +    s.push_str("bar");
 +    assert_eq!(s, "bar");
 +
 +    let t = Some(s);
 +    // OK
 +    if let Some(x) = t.clone() {
 +        println!("{}", x);
 +    }
 +    if let Some(x) = t {
 +        println!("{}", x);
 +    }
 +}
 +
 +#[allow(clippy::clone_on_copy)]
 +fn issue_5405() {
 +    let a: [String; 1] = [String::from("foo")];
 +    let _b: String = a[0].clone();
 +
 +    let c: [usize; 2] = [2, 3];
 +    let _d: usize = c[1].clone();
 +}
 +
 +fn manually_drop() {
 +    use std::mem::ManuallyDrop;
 +    use std::sync::Arc;
 +
 +    let a = ManuallyDrop::new(Arc::new("Hello!".to_owned()));
 +    let _ = a.clone(); // OK
 +
 +    let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a));
 +    unsafe {
 +        Arc::from_raw(p);
 +        Arc::from_raw(p);
 +    }
 +}
 +
 +fn clone_then_move_cloned() {
 +    // issue #5973
 +    let x = Some(String::new());
 +    // ok, x is moved while the clone is in use.
 +    assert_eq!(x.clone(), None, "not equal {}", x.unwrap());
 +
 +    // issue #5595
 +    fn foo<F: Fn()>(_: &Alpha, _: F) {}
 +    let x = Alpha;
 +    // ok, data is moved while the clone is in use.
 +    foo(&x, move || {
 +        let _ = x;
 +    });
 +
 +    // issue #6998
 +    struct S(String);
 +    impl S {
 +        fn m(&mut self) {}
 +    }
 +    let mut x = S(String::new());
 +    x.0.clone().chars().for_each(|_| x.m());
 +}
 +
 +fn hashmap_neg() {
 +    // issue 5707
 +    use std::collections::HashMap;
 +    use std::path::PathBuf;
 +
 +    let p = PathBuf::from("/");
 +
 +    let mut h: HashMap<&str, &str> = HashMap::new();
 +    h.insert("orig-p", p.to_str().unwrap());
 +
 +    let mut q = p.clone();
 +    q.push("foo");
 +
 +    println!("{:?} {}", h, q.display());
 +}
 +
 +fn false_negative_5707() {
 +    fn foo(_x: &Alpha, _y: &mut Alpha) {}
 +
 +    let x = Alpha;
 +    let mut y = Alpha;
 +    foo(&x, &mut y);
 +    let _z = x.clone(); // pr 7346 can't lint on `x`
 +    drop(y);
 +}
index bd3d7365229fb83ccd13ca555e53d9941f867c43,0000000000000000000000000000000000000000..2f82aefd928309c23eee5d3c7a0540a2f5335b5a
mode 100644,000000..100644
--- /dev/null
@@@ -1,236 -1,0 +1,236 @@@
- #![allow(clippy::implicit_clone)]
 +// run-rustfix
 +// rustfix-only-machine-applicable
 +
++#![allow(clippy::implicit_clone, clippy::drop_non_drop)]
 +use std::ffi::OsString;
 +use std::path::Path;
 +
 +fn main() {
 +    let _s = ["lorem", "ipsum"].join(" ").to_string();
 +
 +    let s = String::from("foo");
 +    let _s = s.clone();
 +
 +    let s = String::from("foo");
 +    let _s = s.to_string();
 +
 +    let s = String::from("foo");
 +    let _s = s.to_owned();
 +
 +    let _s = Path::new("/a/b/").join("c").to_owned();
 +
 +    let _s = Path::new("/a/b/").join("c").to_path_buf();
 +
 +    let _s = OsString::new().to_owned();
 +
 +    let _s = OsString::new().to_os_string();
 +
 +    // Check that lint level works
 +    #[allow(clippy::redundant_clone)]
 +    let _s = String::new().to_string();
 +
 +    let tup = (String::from("foo"),);
 +    let _t = tup.0.clone();
 +
 +    let tup_ref = &(String::from("foo"),);
 +    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
 +
 +    {
 +        let x = String::new();
 +        let y = &x;
 +
 +        let _x = x.clone(); // ok; `x` is borrowed by `y`
 +
 +        let _ = y.len();
 +    }
 +
 +    let x = (String::new(),);
 +    let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x`
 +
 +    with_branch(Alpha, true);
 +    cannot_double_move(Alpha);
 +    cannot_move_from_type_with_drop();
 +    borrower_propagation();
 +    not_consumed();
 +    issue_5405();
 +    manually_drop();
 +    clone_then_move_cloned();
 +    hashmap_neg();
 +    false_negative_5707();
 +}
 +
 +#[derive(Clone)]
 +struct Alpha;
 +fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
 +    if b { (a.clone(), a.clone()) } else { (Alpha, a) }
 +}
 +
 +fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) {
 +    (a.clone(), a)
 +}
 +
 +struct TypeWithDrop {
 +    x: String,
 +}
 +
 +impl Drop for TypeWithDrop {
 +    fn drop(&mut self) {}
 +}
 +
 +fn cannot_move_from_type_with_drop() -> String {
 +    let s = TypeWithDrop { x: String::new() };
 +    s.x.clone() // removing this `clone()` summons E0509
 +}
 +
 +fn borrower_propagation() {
 +    let s = String::new();
 +    let t = String::new();
 +
 +    {
 +        fn b() -> bool {
 +            unimplemented!()
 +        }
 +        let _u = if b() { &s } else { &t };
 +
 +        // ok; `s` and `t` are possibly borrowed
 +        let _s = s.clone();
 +        let _t = t.clone();
 +    }
 +
 +    {
 +        let _u = || s.len();
 +        let _v = [&t; 32];
 +        let _s = s.clone(); // ok
 +        let _t = t.clone(); // ok
 +    }
 +
 +    {
 +        let _u = {
 +            let u = Some(&s);
 +            let _ = s.clone(); // ok
 +            u
 +        };
 +        let _s = s.clone(); // ok
 +    }
 +
 +    {
 +        use std::convert::identity as id;
 +        let _u = id(id(&s));
 +        let _s = s.clone(); // ok, `u` borrows `s`
 +    }
 +
 +    let _s = s.clone();
 +    let _t = t.clone();
 +
 +    #[derive(Clone)]
 +    struct Foo {
 +        x: usize,
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = Some(f.x);
 +        let _f = f.clone();
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = &f.x;
 +        let _f = f.clone(); // ok
 +    }
 +}
 +
 +fn not_consumed() {
 +    let x = std::path::PathBuf::from("home");
 +    let y = x.clone().join("matthias");
 +    // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is
 +    // redundant. (It also does not consume the PathBuf)
 +
 +    println!("x: {:?}, y: {:?}", x, y);
 +
 +    let mut s = String::new();
 +    s.clone().push_str("foo"); // OK, removing this `clone()` will change the behavior.
 +    s.push_str("bar");
 +    assert_eq!(s, "bar");
 +
 +    let t = Some(s);
 +    // OK
 +    if let Some(x) = t.clone() {
 +        println!("{}", x);
 +    }
 +    if let Some(x) = t {
 +        println!("{}", x);
 +    }
 +}
 +
 +#[allow(clippy::clone_on_copy)]
 +fn issue_5405() {
 +    let a: [String; 1] = [String::from("foo")];
 +    let _b: String = a[0].clone();
 +
 +    let c: [usize; 2] = [2, 3];
 +    let _d: usize = c[1].clone();
 +}
 +
 +fn manually_drop() {
 +    use std::mem::ManuallyDrop;
 +    use std::sync::Arc;
 +
 +    let a = ManuallyDrop::new(Arc::new("Hello!".to_owned()));
 +    let _ = a.clone(); // OK
 +
 +    let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a));
 +    unsafe {
 +        Arc::from_raw(p);
 +        Arc::from_raw(p);
 +    }
 +}
 +
 +fn clone_then_move_cloned() {
 +    // issue #5973
 +    let x = Some(String::new());
 +    // ok, x is moved while the clone is in use.
 +    assert_eq!(x.clone(), None, "not equal {}", x.unwrap());
 +
 +    // issue #5595
 +    fn foo<F: Fn()>(_: &Alpha, _: F) {}
 +    let x = Alpha;
 +    // ok, data is moved while the clone is in use.
 +    foo(&x.clone(), move || {
 +        let _ = x;
 +    });
 +
 +    // issue #6998
 +    struct S(String);
 +    impl S {
 +        fn m(&mut self) {}
 +    }
 +    let mut x = S(String::new());
 +    x.0.clone().chars().for_each(|_| x.m());
 +}
 +
 +fn hashmap_neg() {
 +    // issue 5707
 +    use std::collections::HashMap;
 +    use std::path::PathBuf;
 +
 +    let p = PathBuf::from("/");
 +
 +    let mut h: HashMap<&str, &str> = HashMap::new();
 +    h.insert("orig-p", p.to_str().unwrap());
 +
 +    let mut q = p.clone();
 +    q.push("foo");
 +
 +    println!("{:?} {}", h, q.display());
 +}
 +
 +fn false_negative_5707() {
 +    fn foo(_x: &Alpha, _y: &mut Alpha) {}
 +
 +    let x = Alpha;
 +    let mut y = Alpha;
 +    foo(&x, &mut y);
 +    let _z = x.clone(); // pr 7346 can't lint on `x`
 +    drop(y);
 +}
index 921249606ad2716da28f748c27da23342d52123d,0000000000000000000000000000000000000000..acc8f1e25b6ed3a937186d5146275271ad46c0d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,56 -1,0 +1,56 @@@
- struct Foo {}
 +// run-rustfix
 +
 +#![allow(unused)]
 +
 +#[derive(Debug)]
++struct Foo;
 +
 +const VAR_ONE: &str = "Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
 +
 +const VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +
 +const VAR_SIX: &u8 = &5;
 +
 +const VAR_HEIGHT: &Foo = &Foo {};
 +
 +const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
 +
 +static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +static STATIC_VAR_SIX: &u8 = &5;
 +
 +static STATIC_VAR_HEIGHT: &Foo = &Foo {};
 +
 +static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +fn main() {
 +    let false_positive: &'static str = "test";
 +}
 +
 +trait Bar {
 +    const TRAIT_VAR: &'static str;
 +}
 +
 +impl Foo {
 +    const IMPL_VAR: &'static str = "var";
 +}
 +
 +impl Bar for Foo {
 +    const TRAIT_VAR: &'static str = "foo";
 +}
index 4d4b249d076ffca81ecd13eca4022b2e960c5c38,0000000000000000000000000000000000000000..f2f0f78659c936516fab442fd624e1ba7f5164a0
mode 100644,000000..100644
--- /dev/null
@@@ -1,56 -1,0 +1,56 @@@
- struct Foo {}
 +// run-rustfix
 +
 +#![allow(unused)]
 +
 +#[derive(Debug)]
++struct Foo;
 +
 +const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning.
 +
 +const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
 +
 +const VAR_SIX: &'static u8 = &5;
 +
 +const VAR_HEIGHT: &'static Foo = &Foo {};
 +
 +const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
 +
 +const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
 +
 +static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
 +
 +static STATIC_VAR_SIX: &'static u8 = &5;
 +
 +static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
 +
 +static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
 +
 +static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 +
 +fn main() {
 +    let false_positive: &'static str = "test";
 +}
 +
 +trait Bar {
 +    const TRAIT_VAR: &'static str;
 +}
 +
 +impl Foo {
 +    const IMPL_VAR: &'static str = "var";
 +}
 +
 +impl Bar for Foo {
 +    const TRAIT_VAR: &'static str = "foo";
 +}
index 631042c616bc0cd261579f32aa06c43e9526b151,0000000000000000000000000000000000000000..14c331f67e739c34ca722ff0776a83fbe88f5566
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,82 @@@
 +// run-rustfix
 +
 +#![warn(clippy::result_map_unit_fn)]
 +#![allow(unused)]
 +
 +fn do_nothing<T>(_: T) {}
 +
 +fn diverge<T>(_: T) -> ! {
 +    panic!()
 +}
 +
 +fn plus_one(value: usize) -> usize {
 +    value + 1
 +}
 +
 +struct HasResult {
 +    field: Result<usize, usize>,
 +}
 +
 +impl HasResult {
 +    fn do_result_nothing(&self, value: usize) {}
 +
 +    fn do_result_plus_one(&self, value: usize) -> usize {
 +        value + 1
 +    }
 +}
 +
 +#[rustfmt::skip]
 +fn result_map_unit_fn() {
 +    let x = HasResult { field: Ok(10) };
 +
 +    x.field.map(plus_one);
 +    let _: Result<(), usize> = x.field.map(do_nothing);
 +
 +    if let Ok(x_field) = x.field { do_nothing(x_field) }
 +
 +    if let Ok(x_field) = x.field { do_nothing(x_field) }
 +
 +    if let Ok(x_field) = x.field { diverge(x_field) }
 +
 +    let captured = 10;
 +    if let Ok(value) = x.field { do_nothing(value + captured) };
 +    let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
 +
 +    if let Ok(value) = x.field { x.do_result_nothing(value + captured) }
 +
 +    if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }
 +
 +
 +    if let Ok(value) = x.field { do_nothing(value + captured) }
 +
 +    if let Ok(value) = x.field { do_nothing(value + captured) }
 +
 +    if let Ok(value) = x.field { do_nothing(value + captured); }
 +
 +    if let Ok(value) = x.field { do_nothing(value + captured); }
 +
 +
 +    if let Ok(value) = x.field { diverge(value + captured) }
 +
 +    if let Ok(value) = x.field { diverge(value + captured) }
 +
 +    if let Ok(value) = x.field { diverge(value + captured); }
 +
 +    if let Ok(value) = x.field { diverge(value + captured); }
 +
 +
 +    x.field.map(|value| plus_one(value + captured));
 +    x.field.map(|value| { plus_one(value + captured) });
 +    if let Ok(value) = x.field { let y = plus_one(value + captured); }
 +
 +    if let Ok(value) = x.field { plus_one(value + captured); }
 +
 +    if let Ok(value) = x.field { plus_one(value + captured); }
 +
 +
 +    if let Ok(ref value) = x.field { do_nothing(value + captured) }
++
++    if let Ok(value) = x.field { println!("{:?}", value) }
 +}
 +
 +fn main() {}
index 679eb2326268c7a62fba3a04b228d9bbf4a827ee,0000000000000000000000000000000000000000..8b0fca9ece1a375d45e532a5eda015265db5a383
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,82 @@@
 +// run-rustfix
 +
 +#![warn(clippy::result_map_unit_fn)]
 +#![allow(unused)]
 +
 +fn do_nothing<T>(_: T) {}
 +
 +fn diverge<T>(_: T) -> ! {
 +    panic!()
 +}
 +
 +fn plus_one(value: usize) -> usize {
 +    value + 1
 +}
 +
 +struct HasResult {
 +    field: Result<usize, usize>,
 +}
 +
 +impl HasResult {
 +    fn do_result_nothing(&self, value: usize) {}
 +
 +    fn do_result_plus_one(&self, value: usize) -> usize {
 +        value + 1
 +    }
 +}
 +
 +#[rustfmt::skip]
 +fn result_map_unit_fn() {
 +    let x = HasResult { field: Ok(10) };
 +
 +    x.field.map(plus_one);
 +    let _: Result<(), usize> = x.field.map(do_nothing);
 +
 +    x.field.map(do_nothing);
 +
 +    x.field.map(do_nothing);
 +
 +    x.field.map(diverge);
 +
 +    let captured = 10;
 +    if let Ok(value) = x.field { do_nothing(value + captured) };
 +    let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
 +
 +    x.field.map(|value| x.do_result_nothing(value + captured));
 +
 +    x.field.map(|value| { x.do_result_plus_one(value + captured); });
 +
 +
 +    x.field.map(|value| do_nothing(value + captured));
 +
 +    x.field.map(|value| { do_nothing(value + captured) });
 +
 +    x.field.map(|value| { do_nothing(value + captured); });
 +
 +    x.field.map(|value| { { do_nothing(value + captured); } });
 +
 +
 +    x.field.map(|value| diverge(value + captured));
 +
 +    x.field.map(|value| { diverge(value + captured) });
 +
 +    x.field.map(|value| { diverge(value + captured); });
 +
 +    x.field.map(|value| { { diverge(value + captured); } });
 +
 +
 +    x.field.map(|value| plus_one(value + captured));
 +    x.field.map(|value| { plus_one(value + captured) });
 +    x.field.map(|value| { let y = plus_one(value + captured); });
 +
 +    x.field.map(|value| { plus_one(value + captured); });
 +
 +    x.field.map(|value| { { plus_one(value + captured); } });
 +
 +
 +    x.field.map(|ref value| { do_nothing(value + captured) });
++
++    x.field.map(|value| println!("{:?}", value));
 +}
 +
 +fn main() {}
index 4f3a8c6b7923986359d770df58bdc6e530410983,0000000000000000000000000000000000000000..782febd52644128e0e7e18e4c1f4316efbb33b9e
mode 100644,000000..100644
--- /dev/null
@@@ -1,140 -1,0 +1,148 @@@
- error: aborting due to 17 previous errors
 +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:35:5
 +   |
 +LL |     x.field.map(do_nothing);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
 +   |
 +   = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 +
 +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:37:5
 +   |
 +LL |     x.field.map(do_nothing);
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:39:5
 +   |
 +LL |     x.field.map(diverge);
 +   |     ^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:45:5
 +   |
 +LL |     x.field.map(|value| x.do_result_nothing(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:47:5
 +   |
 +LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:50:5
 +   |
 +LL |     x.field.map(|value| do_nothing(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:52:5
 +   |
 +LL |     x.field.map(|value| { do_nothing(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:54:5
 +   |
 +LL |     x.field.map(|value| { do_nothing(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:56:5
 +   |
 +LL |     x.field.map(|value| { { do_nothing(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:59:5
 +   |
 +LL |     x.field.map(|value| diverge(value + captured));
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:61:5
 +   |
 +LL |     x.field.map(|value| { diverge(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:63:5
 +   |
 +LL |     x.field.map(|value| { diverge(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:65:5
 +   |
 +LL |     x.field.map(|value| { { diverge(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:70:5
 +   |
 +LL |     x.field.map(|value| { let y = plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:72:5
 +   |
 +LL |     x.field.map(|value| { plus_one(value + captured); });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:74:5
 +   |
 +LL |     x.field.map(|value| { { plus_one(value + captured); } });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 +
 +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
 +  --> $DIR/result_map_unit_fn_fixable.rs:77:5
 +   |
 +LL |     x.field.map(|ref value| { do_nothing(value + captured) });
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
 +   |     |
 +   |     help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }`
 +
++error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
++  --> $DIR/result_map_unit_fn_fixable.rs:79:5
++   |
++LL |     x.field.map(|value| println!("{:?}", value));
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
++   |     |
++   |     help: try this: `if let Ok(value) = x.field { println!("{:?}", value) }`
++
++error: aborting due to 18 previous errors
 +
index 9d420ec672a26da73e827a620c36de4ddeb3bc75,0000000000000000000000000000000000000000..99964f0de075c04a53467f12fd732e2f97a9506e
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,158 @@@
-     struct S {}
 +#![warn(clippy::same_item_push)]
 +
 +const VALUE: u8 = 7;
 +
 +fn mutate_increment(x: &mut u8) -> u8 {
 +    *x += 1;
 +    *x
 +}
 +
 +fn increment(x: u8) -> u8 {
 +    x + 1
 +}
 +
 +fn fun() -> usize {
 +    42
 +}
 +
 +fn main() {
 +    // ** linted cases **
 +    let mut vec: Vec<u8> = Vec::new();
 +    let item = 2;
 +    for _ in 5..=20 {
 +        vec.push(item);
 +    }
 +
 +    let mut vec: Vec<u8> = Vec::new();
 +    for _ in 0..15 {
 +        let item = 2;
 +        vec.push(item);
 +    }
 +
 +    let mut vec: Vec<u8> = Vec::new();
 +    for _ in 0..15 {
 +        vec.push(13);
 +    }
 +
 +    let mut vec = Vec::new();
 +    for _ in 0..20 {
 +        vec.push(VALUE);
 +    }
 +
 +    let mut vec = Vec::new();
 +    let item = VALUE;
 +    for _ in 0..20 {
 +        vec.push(item);
 +    }
 +
 +    // ** non-linted cases **
 +    let mut spaces = Vec::with_capacity(10);
 +    for _ in 0..10 {
 +        spaces.push(vec![b' ']);
 +    }
 +
 +    // Suggestion should not be given as pushed variable can mutate
 +    let mut vec: Vec<u8> = Vec::new();
 +    let mut item: u8 = 2;
 +    for _ in 0..30 {
 +        vec.push(mutate_increment(&mut item));
 +    }
 +
 +    let mut vec: Vec<u8> = Vec::new();
 +    let mut item: u8 = 2;
 +    let mut item2 = &mut mutate_increment(&mut item);
 +    for _ in 0..30 {
 +        vec.push(mutate_increment(item2));
 +    }
 +
 +    let mut vec: Vec<usize> = Vec::new();
 +    for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() {
 +        vec.push(a);
 +    }
 +
 +    let mut vec: Vec<u8> = Vec::new();
 +    for i in 0..30 {
 +        vec.push(increment(i));
 +    }
 +
 +    let mut vec: Vec<u8> = Vec::new();
 +    for i in 0..30 {
 +        vec.push(i + i * i);
 +    }
 +
 +    // Suggestion should not be given as there are multiple pushes that are not the same
 +    let mut vec: Vec<u8> = Vec::new();
 +    let item: u8 = 2;
 +    for _ in 0..30 {
 +        vec.push(item);
 +        vec.push(item * 2);
 +    }
 +
 +    // Suggestion should not be given as Vec is not involved
 +    for _ in 0..5 {
 +        println!("Same Item Push");
 +    }
 +
 +    struct A {
 +        kind: u32,
 +    }
 +    let mut vec_a: Vec<A> = Vec::new();
 +    for i in 0..30 {
 +        vec_a.push(A { kind: i });
 +    }
 +    let mut vec: Vec<u8> = Vec::new();
 +    for a in vec_a {
 +        vec.push(2u8.pow(a.kind));
 +    }
 +
 +    // Fix #5902
 +    let mut vec: Vec<u8> = Vec::new();
 +    let mut item = 0;
 +    for _ in 0..10 {
 +        vec.push(item);
 +        item += 10;
 +    }
 +
 +    // Fix #5979
 +    let mut vec: Vec<std::fs::File> = Vec::new();
 +    for _ in 0..10 {
 +        vec.push(std::fs::File::open("foobar").unwrap());
 +    }
 +    // Fix #5979
 +    #[derive(Clone)]
++    struct S;
 +
 +    trait T {}
 +    impl T for S {}
 +
 +    let mut vec: Vec<Box<dyn T>> = Vec::new();
 +    for _ in 0..10 {
 +        vec.push(Box::new(S {}));
 +    }
 +
 +    // Fix #5985
 +    let mut vec = Vec::new();
 +    let item = 42;
 +    let item = fun();
 +    for _ in 0..20 {
 +        vec.push(item);
 +    }
 +
 +    // Fix #5985
 +    let mut vec = Vec::new();
 +    let key = 1;
 +    for _ in 0..20 {
 +        let item = match key {
 +            1 => 10,
 +            _ => 0,
 +        };
 +        vec.push(item);
 +    }
 +
 +    // Fix #6987
 +    let mut vec = Vec::new();
 +    for _ in 0..10 {
 +        vec.push(1);
 +        vec.extend(&[2]);
 +    }
 +}
index c307afffcb86325b7dac857ef288042e1a5bdce9,0000000000000000000000000000000000000000..63d31ff83f9b5c508f09fa556ba5ee2421bd0cc4
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,36 @@@
-         println!("{}", item);
 +// run-rustfix
 +// Tests from for_loop.rs that don't have suggestions
 +
 +#[warn(clippy::single_element_loop)]
 +fn main() {
 +    let item1 = 2;
 +    {
 +        let item = &item1;
-         println!("{:?}", item);
++        dbg!(item);
 +    }
 +
 +    {
 +        let item = &item1;
++        dbg!(item);
++    }
++
++    {
++        let item = &(0..5);
++        dbg!(item);
++    }
++
++    {
++        let item = &mut (0..5);
++        dbg!(item);
++    }
++
++    {
++        let item = 0..5;
++        dbg!(item);
++    }
++
++    {
++        let item = 0..5;
++        dbg!(item);
 +    }
 +}
index 2c0c03b7211993ee22d5c5022818eec6842cb283,0000000000000000000000000000000000000000..2cda5a329d254fb496dec9dca41bfa899142ed4c
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,30 @@@
-         println!("{}", item);
 +// run-rustfix
 +// Tests from for_loop.rs that don't have suggestions
 +
 +#[warn(clippy::single_element_loop)]
 +fn main() {
 +    let item1 = 2;
 +    for item in &[item1] {
-         println!("{:?}", item);
++        dbg!(item);
 +    }
 +
 +    for item in [item1].iter() {
++        dbg!(item);
++    }
++
++    for item in &[0..5] {
++        dbg!(item);
++    }
++
++    for item in [0..5].iter_mut() {
++        dbg!(item);
++    }
++
++    for item in [0..5] {
++        dbg!(item);
++    }
++
++    for item in [0..5].into_iter() {
++        dbg!(item);
 +    }
 +}
index f52ca8c5a9b0c35c6cda340763ebc6e4ba74cb17,0000000000000000000000000000000000000000..0aeb8da1a2e23e6dac4c85f1be745ede77c4c830
mode 100644,000000..100644
--- /dev/null
@@@ -1,35 -1,0 +1,99 @@@
- LL | |         println!("{}", item);
 +error: for loop over a single element
 +  --> $DIR/single_element_loop.rs:7:5
 +   |
 +LL | /     for item in &[item1] {
- LL +         println!("{}", item);
++LL | |         dbg!(item);
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::single-element-loop` implied by `-D warnings`
 +help: try
 +   |
 +LL ~     {
 +LL +         let item = &item1;
- LL | |         println!("{:?}", item);
++LL +         dbg!(item);
 +LL +     }
 +   |
 +
 +error: for loop over a single element
 +  --> $DIR/single_element_loop.rs:11:5
 +   |
 +LL | /     for item in [item1].iter() {
- LL +         println!("{:?}", item);
++LL | |         dbg!(item);
 +LL | |     }
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     {
 +LL +         let item = &item1;
- error: aborting due to 2 previous errors
++LL +         dbg!(item);
 +LL +     }
 +   |
 +
++error: for loop over a single element
++  --> $DIR/single_element_loop.rs:15:5
++   |
++LL | /     for item in &[0..5] {
++LL | |         dbg!(item);
++LL | |     }
++   | |_____^
++   |
++help: try
++   |
++LL ~     {
++LL +         let item = &(0..5);
++LL +         dbg!(item);
++LL +     }
++   |
++
++error: for loop over a single element
++  --> $DIR/single_element_loop.rs:19:5
++   |
++LL | /     for item in [0..5].iter_mut() {
++LL | |         dbg!(item);
++LL | |     }
++   | |_____^
++   |
++help: try
++   |
++LL ~     {
++LL +         let item = &mut (0..5);
++LL +         dbg!(item);
++LL +     }
++   |
++
++error: for loop over a single element
++  --> $DIR/single_element_loop.rs:23:5
++   |
++LL | /     for item in [0..5] {
++LL | |         dbg!(item);
++LL | |     }
++   | |_____^
++   |
++help: try
++   |
++LL ~     {
++LL +         let item = 0..5;
++LL +         dbg!(item);
++LL +     }
++   |
++
++error: for loop over a single element
++  --> $DIR/single_element_loop.rs:27:5
++   |
++LL | /     for item in [0..5].into_iter() {
++LL | |         dbg!(item);
++LL | |     }
++   | |_____^
++   |
++help: try
++   |
++LL ~     {
++LL +         let item = 0..5;
++LL +         dbg!(item);
++LL +     }
++   |
++
++error: aborting due to 6 previous errors
 +
index 21de19a26014755f493dff4dbf1927798c78aa70,0000000000000000000000000000000000000000..f5ca91143af25683625d19ba51efe22d070e5233
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,98 @@@
- struct Life {}
 +#![deny(clippy::trait_duplication_in_bounds)]
 +
 +use std::collections::BTreeMap;
 +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 +
 +fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
 +where
 +    T: Clone,
 +    T: Default,
 +{
 +    unimplemented!();
 +}
 +
 +fn good_bar<T: Clone + Default>(arg: T) {
 +    unimplemented!();
 +}
 +
 +fn good_foo<T>(arg: T)
 +where
 +    T: Clone + Default,
 +{
 +    unimplemented!();
 +}
 +
 +fn good_foobar<T: Default>(arg: T)
 +where
 +    T: Clone,
 +{
 +    unimplemented!();
 +}
 +
 +trait T: Default {
 +    fn f()
 +    where
 +        Self: Default;
 +}
 +
 +trait U: Default {
 +    fn f()
 +    where
 +        Self: Clone;
 +}
 +
 +trait ZZ: Default {
 +    fn g();
 +    fn h();
 +    fn f()
 +    where
 +        Self: Default + Clone;
 +}
 +
 +trait BadTrait: Default + Clone {
 +    fn f()
 +    where
 +        Self: Default + Clone;
 +    fn g()
 +    where
 +        Self: Default;
 +    fn h()
 +    where
 +        Self: Copy;
 +}
 +
 +#[derive(Default, Clone)]
- struct Foo {}
++struct Life;
 +
 +impl T for Life {
 +    // this should not warn
 +    fn f() {}
 +}
 +
 +impl U for Life {
 +    // this should not warn
 +    fn f() {}
 +}
 +
 +// should not warn
 +trait Iter: Iterator {
 +    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
 +    where
 +        Self: Iterator<Item = (K, V)> + Sized,
 +        K: Ord + Eq,
 +    {
 +        unimplemented!();
 +    }
 +}
 +
++struct Foo;
 +
 +trait FooIter: Iterator<Item = Foo> {
 +    fn bar()
 +    where
 +        Self: Iterator<Item = Foo>,
 +    {
 +    }
 +}
 +
 +fn main() {}
index 9b681a79aae7a385f922a6c04aaf2cd06b37bd94,0000000000000000000000000000000000000000..5b688ce4d644f766881cf36b74e3648df9c2f061
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,145 @@@
- fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
-     let _: &str = unsafe { std::mem::transmute(b) };
 +#![allow(dead_code, clippy::borrow_as_ptr)]
 +
 +extern crate core;
 +
 +use std::mem::transmute as my_transmute;
 +use std::vec::Vec as MyVec;
 +
 +fn my_int() -> Usize {
 +    Usize(42)
 +}
 +
 +fn my_vec() -> MyVec<i32> {
 +    vec![]
 +}
 +
 +#[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
 +#[warn(clippy::useless_transmute)]
 +unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
 +    let _: &'a T = core::intrinsics::transmute(t);
 +
 +    let _: &'a U = core::intrinsics::transmute(t);
 +
 +    let _: *const T = core::intrinsics::transmute(t);
 +
 +    let _: *mut T = core::intrinsics::transmute(t);
 +
 +    let _: *const U = core::intrinsics::transmute(t);
 +}
 +
 +#[warn(clippy::useless_transmute)]
 +fn useless() {
 +    unsafe {
 +        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
 +
 +        let _: Vec<i32> = core::mem::transmute(my_vec());
 +
 +        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
 +
 +        let _: Vec<i32> = std::mem::transmute(my_vec());
 +
 +        let _: Vec<i32> = my_transmute(my_vec());
 +
 +        let _: *const usize = std::mem::transmute(5_isize);
 +
 +        let _ = 5_isize as *const usize;
 +
 +        let _: *const usize = std::mem::transmute(1 + 1usize);
 +
 +        let _ = (1 + 1_usize) as *const usize;
 +    }
 +}
 +
 +struct Usize(usize);
 +
 +#[warn(clippy::crosspointer_transmute)]
 +fn crosspointer() {
 +    let mut int: Usize = Usize(0);
 +    let int_const_ptr: *const Usize = &int as *const Usize;
 +    let int_mut_ptr: *mut Usize = &mut int as *mut Usize;
 +
 +    unsafe {
 +        let _: Usize = core::intrinsics::transmute(int_const_ptr);
 +
 +        let _: Usize = core::intrinsics::transmute(int_mut_ptr);
 +
 +        let _: *const Usize = core::intrinsics::transmute(my_int());
 +
 +        let _: *mut Usize = core::intrinsics::transmute(my_int());
 +    }
 +}
 +
 +#[warn(clippy::transmute_int_to_char)]
 +fn int_to_char() {
 +    let _: char = unsafe { std::mem::transmute(0_u32) };
 +    let _: char = unsafe { std::mem::transmute(0_i32) };
++
++    // These shouldn't warn
++    const _: char = unsafe { std::mem::transmute(0_u32) };
++    const _: char = unsafe { std::mem::transmute(0_i32) };
 +}
 +
 +#[warn(clippy::transmute_int_to_bool)]
 +fn int_to_bool() {
 +    let _: bool = unsafe { std::mem::transmute(0_u8) };
 +}
 +
 +#[warn(clippy::transmute_int_to_float)]
 +mod int_to_float {
 +    fn test() {
 +        let _: f32 = unsafe { std::mem::transmute(0_u32) };
 +        let _: f32 = unsafe { std::mem::transmute(0_i32) };
 +        let _: f64 = unsafe { std::mem::transmute(0_u64) };
 +        let _: f64 = unsafe { std::mem::transmute(0_i64) };
 +    }
 +
 +    mod issue_5747 {
 +        const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
 +        const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
 +
 +        const fn from_bits_32(v: i32) -> f32 {
 +            unsafe { std::mem::transmute(v) }
 +        }
 +
 +        const fn from_bits_64(v: u64) -> f64 {
 +            unsafe { std::mem::transmute(v) }
 +        }
 +    }
 +}
 +
 +mod num_to_bytes {
 +    fn test() {
 +        unsafe {
 +            let _: [u8; 1] = std::mem::transmute(0u8);
 +            let _: [u8; 4] = std::mem::transmute(0u32);
 +            let _: [u8; 16] = std::mem::transmute(0u128);
 +            let _: [u8; 1] = std::mem::transmute(0i8);
 +            let _: [u8; 4] = std::mem::transmute(0i32);
 +            let _: [u8; 16] = std::mem::transmute(0i128);
 +            let _: [u8; 4] = std::mem::transmute(0.0f32);
 +            let _: [u8; 8] = std::mem::transmute(0.0f64);
 +        }
 +    }
 +    const fn test_const() {
 +        unsafe {
 +            let _: [u8; 1] = std::mem::transmute(0u8);
 +            let _: [u8; 4] = std::mem::transmute(0u32);
 +            let _: [u8; 16] = std::mem::transmute(0u128);
 +            let _: [u8; 1] = std::mem::transmute(0i8);
 +            let _: [u8; 4] = std::mem::transmute(0i32);
 +            let _: [u8; 16] = std::mem::transmute(0i128);
 +            let _: [u8; 4] = std::mem::transmute(0.0f32);
 +            let _: [u8; 8] = std::mem::transmute(0.0f64);
 +        }
 +    }
 +}
 +
++fn bytes_to_str(mb: &mut [u8]) {
++    const B: &[u8] = b"";
++
++    let _: &str = unsafe { std::mem::transmute(B) };
 +    let _: &mut str = unsafe { std::mem::transmute(mb) };
++    const _: &str = unsafe { std::mem::transmute(B) };
 +}
 +
 +fn main() {}
index 86537153e322897de816064f7b80041c88418c0d,0000000000000000000000000000000000000000..72a386e8fa618f2fe96c5b7f7fc188759c07c161
mode 100644,000000..100644
--- /dev/null
@@@ -1,244 -1,0 +1,250 @@@
-   --> $DIR/transmute.rs:80:28
 +error: transmute from a type (`&T`) to itself
 +  --> $DIR/transmute.rs:19:20
 +   |
 +LL |     let _: &'a T = core::intrinsics::transmute(t);
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::useless-transmute` implied by `-D warnings`
 +
 +error: transmute from a reference to a pointer
 +  --> $DIR/transmute.rs:23:23
 +   |
 +LL |     let _: *const T = core::intrinsics::transmute(t);
 +   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
 +
 +error: transmute from a reference to a pointer
 +  --> $DIR/transmute.rs:25:21
 +   |
 +LL |     let _: *mut T = core::intrinsics::transmute(t);
 +   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 +
 +error: transmute from a reference to a pointer
 +  --> $DIR/transmute.rs:27:23
 +   |
 +LL |     let _: *const U = core::intrinsics::transmute(t);
 +   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
 +  --> $DIR/transmute.rs:33:27
 +   |
 +LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
 +  --> $DIR/transmute.rs:35:27
 +   |
 +LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
 +  --> $DIR/transmute.rs:37:27
 +   |
 +LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
 +  --> $DIR/transmute.rs:39:27
 +   |
 +LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`std::vec::Vec<i32>`) to itself
 +  --> $DIR/transmute.rs:41:27
 +   |
 +LL |         let _: Vec<i32> = my_transmute(my_vec());
 +   |                           ^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from an integer to a pointer
 +  --> $DIR/transmute.rs:43:31
 +   |
 +LL |         let _: *const usize = std::mem::transmute(5_isize);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 +
 +error: transmute from an integer to a pointer
 +  --> $DIR/transmute.rs:47:31
 +   |
 +LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 +
 +error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
 +  --> $DIR/transmute.rs:62:24
 +   |
 +LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 +
 +error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
 +  --> $DIR/transmute.rs:64:24
 +   |
 +LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
 +   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
 +  --> $DIR/transmute.rs:66:31
 +   |
 +LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
 +  --> $DIR/transmute.rs:68:29
 +   |
 +LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
 +   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: transmute from a `u32` to a `char`
 +  --> $DIR/transmute.rs:74:28
 +   |
 +LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
 +   |
 +   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
 +
 +error: transmute from a `i32` to a `char`
 +  --> $DIR/transmute.rs:75:28
 +   |
 +LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
 +
 +error: transmute from a `u8` to a `bool`
-   --> $DIR/transmute.rs:86:31
++  --> $DIR/transmute.rs:84:28
 +   |
 +LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
 +   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
 +   |
 +   = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
 +
 +error: transmute from a `u32` to a `f32`
-   --> $DIR/transmute.rs:87:31
++  --> $DIR/transmute.rs:90:31
 +   |
 +LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
 +   |
 +   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
 +
 +error: transmute from a `i32` to a `f32`
-   --> $DIR/transmute.rs:88:31
++  --> $DIR/transmute.rs:91:31
 +   |
 +LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
 +
 +error: transmute from a `u64` to a `f64`
-   --> $DIR/transmute.rs:89:31
++  --> $DIR/transmute.rs:92:31
 +   |
 +LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
 +
 +error: transmute from a `i64` to a `f64`
-   --> $DIR/transmute.rs:109:30
++  --> $DIR/transmute.rs:93:31
 +   |
 +LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 +
 +error: transmute from a `u8` to a `[u8; 1]`
-   --> $DIR/transmute.rs:110:30
++  --> $DIR/transmute.rs:113:30
 +   |
 +LL |             let _: [u8; 1] = std::mem::transmute(0u8);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
 +   |
 +   = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
 +
 +error: transmute from a `u32` to a `[u8; 4]`
-   --> $DIR/transmute.rs:111:31
++  --> $DIR/transmute.rs:114:30
 +   |
 +LL |             let _: [u8; 4] = std::mem::transmute(0u32);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 +
 +error: transmute from a `u128` to a `[u8; 16]`
-   --> $DIR/transmute.rs:112:30
++  --> $DIR/transmute.rs:115:31
 +   |
 +LL |             let _: [u8; 16] = std::mem::transmute(0u128);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 +
 +error: transmute from a `i8` to a `[u8; 1]`
-   --> $DIR/transmute.rs:113:30
++  --> $DIR/transmute.rs:116:30
 +   |
 +LL |             let _: [u8; 1] = std::mem::transmute(0i8);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 +
 +error: transmute from a `i32` to a `[u8; 4]`
-   --> $DIR/transmute.rs:114:31
++  --> $DIR/transmute.rs:117:30
 +   |
 +LL |             let _: [u8; 4] = std::mem::transmute(0i32);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 +
 +error: transmute from a `i128` to a `[u8; 16]`
-   --> $DIR/transmute.rs:115:30
++  --> $DIR/transmute.rs:118:31
 +   |
 +LL |             let _: [u8; 16] = std::mem::transmute(0i128);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 +
 +error: transmute from a `f32` to a `[u8; 4]`
-   --> $DIR/transmute.rs:116:30
++  --> $DIR/transmute.rs:119:30
 +   |
 +LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
 +
 +error: transmute from a `f64` to a `[u8; 8]`
-   --> $DIR/transmute.rs:121:30
++  --> $DIR/transmute.rs:120:30
 +   |
 +LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
 +
 +error: transmute from a `u8` to a `[u8; 1]`
-   --> $DIR/transmute.rs:122:30
++  --> $DIR/transmute.rs:125:30
 +   |
 +LL |             let _: [u8; 1] = std::mem::transmute(0u8);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
 +
 +error: transmute from a `u32` to a `[u8; 4]`
-   --> $DIR/transmute.rs:123:31
++  --> $DIR/transmute.rs:126:30
 +   |
 +LL |             let _: [u8; 4] = std::mem::transmute(0u32);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 +
 +error: transmute from a `u128` to a `[u8; 16]`
-   --> $DIR/transmute.rs:124:30
++  --> $DIR/transmute.rs:127:31
 +   |
 +LL |             let _: [u8; 16] = std::mem::transmute(0u128);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 +
 +error: transmute from a `i8` to a `[u8; 1]`
-   --> $DIR/transmute.rs:125:30
++  --> $DIR/transmute.rs:128:30
 +   |
 +LL |             let _: [u8; 1] = std::mem::transmute(0i8);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 +
 +error: transmute from a `i32` to a `[u8; 4]`
-   --> $DIR/transmute.rs:126:31
++  --> $DIR/transmute.rs:129:30
 +   |
 +LL |             let _: [u8; 4] = std::mem::transmute(0i32);
 +   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 +
 +error: transmute from a `i128` to a `[u8; 16]`
-   --> $DIR/transmute.rs:134:28
++  --> $DIR/transmute.rs:130:31
 +   |
 +LL |             let _: [u8; 16] = std::mem::transmute(0i128);
 +   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 +
 +error: transmute from a `&[u8]` to a `&str`
- LL |     let _: &str = unsafe { std::mem::transmute(b) };
-    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
++  --> $DIR/transmute.rs:140:28
 +   |
-   --> $DIR/transmute.rs:135:32
++LL |     let _: &str = unsafe { std::mem::transmute(B) };
++   |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
 +   |
 +   = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 +
 +error: transmute from a `&mut [u8]` to a `&mut str`
- error: aborting due to 38 previous errors
++  --> $DIR/transmute.rs:141:32
 +   |
 +LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
 +   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 +
++error: transmute from a `&[u8]` to a `&str`
++  --> $DIR/transmute.rs:142:30
++   |
++LL |     const _: &str = unsafe { std::mem::transmute(B) };
++   |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
++
++error: aborting due to 39 previous errors
 +
index 380303d8152aae2bfc56d37e7a09ddf660f46302,0000000000000000000000000000000000000000..afa337c45f41766033abe0d1d85b2694f7fa11f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,291 -1,0 +1,336 @@@
- #[rustfmt::skip]
- fn inline_block_comment() {
-     /* Safety: */unsafe {}
- }
++// aux-build:proc_macro_unsafe.rs
++
 +#![warn(clippy::undocumented_unsafe_blocks)]
 +
++extern crate proc_macro_unsafe;
++
 +// Valid comments
 +
 +fn nested_local() {
 +    let _ = {
 +        let _ = {
 +            // SAFETY:
 +            let _ = unsafe {};
 +        };
 +    };
 +}
 +
 +fn deep_nest() {
 +    let _ = {
 +        let _ = {
 +            // SAFETY:
 +            let _ = unsafe {};
 +
 +            // Safety:
 +            unsafe {};
 +
 +            let _ = {
 +                let _ = {
 +                    let _ = {
 +                        let _ = {
 +                            let _ = {
 +                                // Safety:
 +                                let _ = unsafe {};
 +
 +                                // SAFETY:
 +                                unsafe {};
 +                            };
 +                        };
 +                    };
 +
 +                    // Safety:
 +                    unsafe {};
 +                };
 +            };
 +        };
 +
 +        // Safety:
 +        unsafe {};
 +    };
 +
 +    // SAFETY:
 +    unsafe {};
 +}
 +
 +fn local_tuple_expression() {
 +    // Safety:
 +    let _ = (42, unsafe {});
 +}
 +
 +fn line_comment() {
 +    // Safety:
 +    unsafe {}
 +}
 +
 +fn line_comment_newlines() {
 +    // SAFETY:
 +
 +    unsafe {}
 +}
 +
 +fn line_comment_empty() {
 +    // Safety:
 +    //
 +    //
 +    //
 +    unsafe {}
 +}
 +
 +fn line_comment_with_extras() {
 +    // This is a description
 +    // Safety:
 +    unsafe {}
 +}
 +
 +fn block_comment() {
 +    /* Safety: */
 +    unsafe {}
 +}
 +
 +fn block_comment_newlines() {
 +    /* SAFETY: */
 +
 +    unsafe {}
 +}
 +
 +fn block_comment_with_extras() {
 +    /* This is a description
 +     * SAFETY:
 +     */
 +    unsafe {}
 +}
 +
 +fn block_comment_terminator_same_line() {
 +    /* This is a description
 +     * Safety: */
 +    unsafe {}
 +}
 +
 +fn buried_safety() {
 +    // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
 +    // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
 +    // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
 +    // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
 +    // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
 +    // laborum. Safety:
 +    // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
 +    // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
 +    // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
 +    // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
 +    unsafe {}
 +}
 +
 +fn safety_with_prepended_text() {
 +    // This is a test. safety:
 +    unsafe {}
 +}
 +
 +fn local_line_comment() {
 +    // Safety:
 +    let _ = unsafe {};
 +}
 +
 +fn local_block_comment() {
 +    /* SAFETY: */
 +    let _ = unsafe {};
 +}
 +
 +fn comment_array() {
 +    // Safety:
 +    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +}
 +
 +fn comment_tuple() {
 +    // sAFETY:
 +    let _ = (42, unsafe {}, "test", unsafe {});
 +}
 +
 +fn comment_unary() {
 +    // SAFETY:
 +    let _ = *unsafe { &42 };
 +}
 +
 +#[allow(clippy::match_single_binding)]
 +fn comment_match() {
 +    // SAFETY:
 +    let _ = match unsafe {} {
 +        _ => {},
 +    };
 +}
 +
 +fn comment_addr_of() {
 +    // Safety:
 +    let _ = &unsafe {};
 +}
 +
 +fn comment_repeat() {
 +    // Safety:
 +    let _ = [unsafe {}; 5];
 +}
 +
 +fn comment_macro_call() {
 +    macro_rules! t {
 +        ($b:expr) => {
 +            $b
 +        };
 +    }
 +
 +    t!(
 +        // SAFETY:
 +        unsafe {}
 +    );
 +}
 +
 +fn comment_macro_def() {
 +    macro_rules! t {
 +        () => {
 +            // Safety:
 +            unsafe {}
 +        };
 +    }
 +
 +    t!();
 +}
 +
 +fn non_ascii_comment() {
 +    // ॐ᧻໒ SaFeTy: ௵∰
 +    unsafe {};
 +}
 +
 +fn local_commented_block() {
 +    let _ =
 +        // safety:
 +        unsafe {};
 +}
 +
 +fn local_nest() {
 +    // safety:
 +    let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
 +}
 +
++fn in_fn_call(x: *const u32) {
++    fn f(x: u32) {}
++
++    // Safety: reason
++    f(unsafe { *x });
++}
++
++fn multi_in_fn_call(x: *const u32) {
++    fn f(x: u32, y: u32) {}
++
++    // Safety: reason
++    f(unsafe { *x }, unsafe { *x });
++}
++
++fn in_multiline_fn_call(x: *const u32) {
++    fn f(x: u32, y: u32) {}
++
++    f(
++        // Safety: reason
++        unsafe { *x },
++        0,
++    );
++}
++
++fn in_macro_call(x: *const u32) {
++    // Safety: reason
++    println!("{}", unsafe { *x });
++}
++
++fn in_multiline_macro_call(x: *const u32) {
++    println!(
++        "{}",
++        // Safety: reason
++        unsafe { *x },
++    );
++}
++
++fn from_proc_macro() {
++    proc_macro_unsafe::unsafe_block!(token);
++}
++
 +// Invalid comments
 +
++#[rustfmt::skip]
++fn inline_block_comment() {
++    /* Safety: */ unsafe {}
++}
++
 +fn no_comment() {
 +    unsafe {}
 +}
 +
 +fn no_comment_array() {
 +    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
 +}
 +
 +fn no_comment_tuple() {
 +    let _ = (42, unsafe {}, "test", unsafe {});
 +}
 +
 +fn no_comment_unary() {
 +    let _ = *unsafe { &42 };
 +}
 +
 +#[allow(clippy::match_single_binding)]
 +fn no_comment_match() {
 +    let _ = match unsafe {} {
 +        _ => {},
 +    };
 +}
 +
 +fn no_comment_addr_of() {
 +    let _ = &unsafe {};
 +}
 +
 +fn no_comment_repeat() {
 +    let _ = [unsafe {}; 5];
 +}
 +
 +fn local_no_comment() {
 +    let _ = unsafe {};
 +}
 +
 +fn no_comment_macro_call() {
 +    macro_rules! t {
 +        ($b:expr) => {
 +            $b
 +        };
 +    }
 +
 +    t!(unsafe {});
 +}
 +
 +fn no_comment_macro_def() {
 +    macro_rules! t {
 +        () => {
 +            unsafe {}
 +        };
 +    }
 +
 +    t!();
 +}
 +
 +fn trailing_comment() {
 +    unsafe {} // SAFETY:
 +}
 +
 +fn internal_comment() {
 +    unsafe {
 +        // SAFETY:
 +    }
 +}
 +
 +fn interference() {
 +    // SAFETY
 +
 +    let _ = 42;
 +
 +    unsafe {};
 +}
 +
 +pub fn print_binary_tree() {
 +    println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
 +}
 +
 +fn main() {}
index f69d0da54e0d6cf4fdb21a80aa73244b5d38e7c5,0000000000000000000000000000000000000000..856a07fd31685e3170eba2ff3baf47221494cf01
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,151 @@@
-   --> $DIR/undocumented_unsafe_blocks.rs:215:5
 +error: unsafe block missing a safety comment
-    = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
- help: consider adding a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:256:19
++   |
++LL |     /* Safety: */ unsafe {}
++   |                   ^^^^^^^^^
++   |
++   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
++   = help: consider adding a safety comment on the preceding line
++
++error: unsafe block missing a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:260:5
 +   |
 +LL |     unsafe {}
 +   |     ^^^^^^^^^
 +   |
- LL ~     // SAFETY: ...
- LL +     unsafe {}
++   = help: consider adding a safety comment on the preceding line
++
++error: unsafe block missing a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:264:14
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:219:5
++LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
++   |              ^^^^^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++  --> $DIR/undocumented_unsafe_blocks.rs:264:29
 +   |
 +LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
- help: consider adding a safety comment
++   |                             ^^^^^^^^^^^^^
 +   |
- LL ~     // SAFETY: ...
- LL +     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
++   = help: consider adding a safety comment on the preceding line
++
++error: unsafe block missing a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:264:48
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:223:5
++LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
++   |                                                ^^^^^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++  --> $DIR/undocumented_unsafe_blocks.rs:268:18
 +   |
 +LL |     let _ = (42, unsafe {}, "test", unsafe {});
- help: consider adding a safety comment
++   |                  ^^^^^^^^^
 +   |
- LL ~     // SAFETY: ...
- LL +     let _ = (42, unsafe {}, "test", unsafe {});
++   = help: consider adding a safety comment on the preceding line
++
++error: unsafe block missing a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:268:37
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:227:5
++LL |     let _ = (42, unsafe {}, "test", unsafe {});
++   |                                     ^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^
-    |
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     let _ = *unsafe { &42 };
++  --> $DIR/undocumented_unsafe_blocks.rs:272:14
 +   |
 +LL |     let _ = *unsafe { &42 };
-   --> $DIR/undocumented_unsafe_blocks.rs:232:5
++   |              ^^^^^^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     let _ = match unsafe {} {
++  --> $DIR/undocumented_unsafe_blocks.rs:277:19
 +   |
 +LL |     let _ = match unsafe {} {
-   --> $DIR/undocumented_unsafe_blocks.rs:238:5
++   |                   ^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^
-    |
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     let _ = &unsafe {};
++  --> $DIR/undocumented_unsafe_blocks.rs:283:14
 +   |
 +LL |     let _ = &unsafe {};
-   --> $DIR/undocumented_unsafe_blocks.rs:242:5
++   |              ^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^^^^^^
-    |
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     let _ = [unsafe {}; 5];
++  --> $DIR/undocumented_unsafe_blocks.rs:287:14
 +   |
 +LL |     let _ = [unsafe {}; 5];
-   --> $DIR/undocumented_unsafe_blocks.rs:246:5
++   |              ^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
-    |     ^^^^^^^^^^^^^^^^^^
-    |
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     let _ = unsafe {};
++  --> $DIR/undocumented_unsafe_blocks.rs:291:13
 +   |
 +LL |     let _ = unsafe {};
-   --> $DIR/undocumented_unsafe_blocks.rs:256:8
++   |             ^^^^^^^^^
 +   |
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
- help: consider adding a safety comment
-    |
- LL ~     t!(// SAFETY: ...
- LL ~     unsafe {});
-    |
++  --> $DIR/undocumented_unsafe_blocks.rs:301:8
 +   |
 +LL |     t!(unsafe {});
 +   |        ^^^^^^^^^
 +   |
- error: unsafe block in macro expansion missing a safety comment
-   --> $DIR/undocumented_unsafe_blocks.rs:262:13
++   = help: consider adding a safety comment on the preceding line
 +
-    = help: consider adding a safety comment in the macro definition
++error: unsafe block missing a safety comment
++  --> $DIR/undocumented_unsafe_blocks.rs:307:13
 +   |
 +LL |             unsafe {}
 +   |             ^^^^^^^^^
 +...
 +LL |     t!();
 +   |     ---- in this macro invocation
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:270:5
++   = help: consider adding a safety comment on the preceding line
 +   = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: unsafe block missing a safety comment
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL ~     unsafe {} // SAFETY:
-    |
++  --> $DIR/undocumented_unsafe_blocks.rs:315:5
 +   |
 +LL |     unsafe {} // SAFETY:
 +   |     ^^^^^^^^^
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:274:5
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL +     unsafe {
-    |
++  --> $DIR/undocumented_unsafe_blocks.rs:319:5
 +   |
 +LL |     unsafe {
 +   |     ^^^^^^^^
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:284:5
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
- help: consider adding a safety comment
-    |
- LL ~     // SAFETY: ...
- LL ~     unsafe {};
-    |
++  --> $DIR/undocumented_unsafe_blocks.rs:329:5
 +   |
 +LL |     unsafe {};
 +   |     ^^^^^^^^^
 +   |
-   --> $DIR/undocumented_unsafe_blocks.rs:288:20
++   = help: consider adding a safety comment on the preceding line
 +
 +error: unsafe block missing a safety comment
- help: consider adding a safety comment
-    |
- LL ~     println!("{}", // SAFETY: ...
- LL ~     unsafe { String::from_utf8_unchecked(vec![]) });
-    |
++  --> $DIR/undocumented_unsafe_blocks.rs:333:20
 +   |
 +LL |     println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
 +   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
- error: aborting due to 14 previous errors
++   = help: consider adding a safety comment on the preceding line
 +
++error: aborting due to 18 previous errors
 +
index b77c19f2ba5961e30409af2c95dd9640978f9ba3,0000000000000000000000000000000000000000..62c3e9636866a5a67492f339ca706b97aea73c31
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,39 @@@
 +#![warn(clippy::unnecessary_cast)]
 +#![allow(clippy::no_effect)]
 +
 +#[rustfmt::skip]
 +fn main() {
 +    // Test cast_unnecessary
 +    1i32 as i32;
 +    1f32 as f32;
 +    false as bool;
 +    &1i32 as &i32;
 +
 +    -1_i32 as i32;
 +    - 1_i32 as i32;
 +    -1f32 as f32;
 +    1_i32 as i32;
 +    1_f32 as f32;
 +
 +    // macro version
 +    macro_rules! foo {
 +        ($a:ident, $b:ident) => {
 +            #[allow(unused)]
 +            pub fn $a() -> $b {
 +                1 as $b
 +            }
 +        };
 +    }
 +    foo!(a, i32);
 +    foo!(b, f32);
 +    foo!(c, f64);
 +
 +    // do not lint cast to cfg-dependant type
 +    1 as std::os::raw::c_char;
++
++    // do not lint cast to alias type
++    1 as I32Alias;
++    &1 as &I32Alias;
 +}
++
++type I32Alias = i32;
index 3332f49c80c9758c2f8cbd61fc19d48a7681dfee,0000000000000000000000000000000000000000..36800c5340db21d665070b288040e00958bd612a
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,50 @@@
 +// run-rustfix
 +
 +#![warn(clippy::unnecessary_cast)]
 +#![allow(
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::nonstandard_macro_braces,
 +    clippy::borrow_as_ptr
 +)]
 +
 +fn main() {
 +    // casting integer literal to float is unnecessary
 +    100_f32;
 +    100_f64;
 +    100_f64;
 +    let _ = -100_f32;
 +    let _ = -100_f64;
 +    let _ = -100_f64;
 +    100_f32;
 +    100_f64;
 +    // Should not trigger
 +    #[rustfmt::skip]
 +    let v = vec!(1);
 +    &v as &[i32];
 +    0x10 as f32;
 +    0o10 as f32;
 +    0b10 as f32;
 +    0x11 as f64;
 +    0o11 as f64;
 +    0b11 as f64;
 +
 +    1_u32;
 +    0x10_i32;
 +    0b10_usize;
 +    0o73_u16;
 +    1_000_000_000_u32;
 +
 +    1.0_f64;
 +    0.5_f32;
 +
 +    1.0 as u16;
 +
 +    let _ = -1_i32;
 +    let _ = -1.0_f32;
++
++    let _ = 1 as I32Alias;
++    let _ = &1 as &I32Alias;
 +}
++
++type I32Alias = i32;
index ec01e93877927af3f51217fe4f194bfb6d8d9645,0000000000000000000000000000000000000000..d4b6bb952ab3508261198212ba394d20b5cd3d4c
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,50 @@@
 +// run-rustfix
 +
 +#![warn(clippy::unnecessary_cast)]
 +#![allow(
 +    clippy::no_effect,
 +    clippy::unnecessary_operation,
 +    clippy::nonstandard_macro_braces,
 +    clippy::borrow_as_ptr
 +)]
 +
 +fn main() {
 +    // casting integer literal to float is unnecessary
 +    100 as f32;
 +    100 as f64;
 +    100_i32 as f64;
 +    let _ = -100 as f32;
 +    let _ = -100 as f64;
 +    let _ = -100_i32 as f64;
 +    100. as f32;
 +    100. as f64;
 +    // Should not trigger
 +    #[rustfmt::skip]
 +    let v = vec!(1);
 +    &v as &[i32];
 +    0x10 as f32;
 +    0o10 as f32;
 +    0b10 as f32;
 +    0x11 as f64;
 +    0o11 as f64;
 +    0b11 as f64;
 +
 +    1 as u32;
 +    0x10 as i32;
 +    0b10 as usize;
 +    0o73 as u16;
 +    1_000_000_000 as u32;
 +
 +    1.0 as f64;
 +    0.5 as f32;
 +
 +    1.0 as u16;
 +
 +    let _ = -1 as i32;
 +    let _ = -1.0 as f32;
++
++    let _ = 1 as I32Alias;
++    let _ = &1 as &I32Alias;
 +}
++
++type I32Alias = i32;
index 690d705573d3f73ae3bba84c7dfb4a97d35e87fb,0000000000000000000000000000000000000000..bafca91917aa431d6747b50a4fee16a4fefe4666
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,70 @@@
- pub struct A {}
 +#![warn(clippy::unsafe_derive_deserialize)]
 +#![allow(unused, clippy::missing_safety_doc)]
 +
 +extern crate serde;
 +
 +use serde::Deserialize;
 +
 +#[derive(Deserialize)]
- pub struct B {}
++pub struct A;
 +impl A {
 +    pub unsafe fn new(_a: i32, _b: i32) -> Self {
 +        Self {}
 +    }
 +}
 +
 +#[derive(Deserialize)]
- pub struct C {}
++pub struct B;
 +impl B {
 +    pub unsafe fn unsafe_method(&self) {}
 +}
 +
 +#[derive(Deserialize)]
- pub struct D {}
++pub struct C;
 +impl C {
 +    pub fn unsafe_block(&self) {
 +        unsafe {}
 +    }
 +}
 +
 +#[derive(Deserialize)]
- pub struct E {}
++pub struct D;
 +impl D {
 +    pub fn inner_unsafe_fn(&self) {
 +        unsafe fn inner() {}
 +    }
 +}
 +
 +// Does not derive `Deserialize`, should be ignored
- pub struct F {}
++pub struct E;
 +impl E {
 +    pub unsafe fn new(_a: i32, _b: i32) -> Self {
 +        Self {}
 +    }
 +
 +    pub unsafe fn unsafe_method(&self) {}
 +
 +    pub fn unsafe_block(&self) {
 +        unsafe {}
 +    }
 +
 +    pub fn inner_unsafe_fn(&self) {
 +        unsafe fn inner() {}
 +    }
 +}
 +
 +// Does not have methods using `unsafe`, should be ignored
 +#[derive(Deserialize)]
- pub struct G {}
++pub struct F;
 +
 +// Check that we honor the `allow` attribute on the ADT
 +#[allow(clippy::unsafe_derive_deserialize)]
 +#[derive(Deserialize)]
++pub struct G;
 +impl G {
 +    pub fn unsafe_block(&self) {
 +        unsafe {}
 +    }
 +}
 +
 +fn main() {}
index a1f616733bd920a277f43afb1e9ce8bdfd865cc3,0000000000000000000000000000000000000000..cde4e96d668c2c78b5cb79478702db0e66520e46
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,27 @@@
-     pub struct Safe {}
-     pub struct Unsafe {}
 +#![allow(unused_imports)]
 +#![allow(dead_code)]
 +#![warn(clippy::unsafe_removed_from_name)]
 +
 +use std::cell::UnsafeCell as TotallySafeCell;
 +
 +use std::cell::UnsafeCell as TotallySafeCellAgain;
 +
 +// Shouldn't error
 +use std::cell::RefCell as ProbablyNotUnsafe;
 +use std::cell::RefCell as RefCellThatCantBeUnsafe;
 +use std::cell::UnsafeCell as SuperDangerousUnsafeCell;
 +use std::cell::UnsafeCell as Dangerunsafe;
 +use std::cell::UnsafeCell as Bombsawayunsafe;
 +
 +mod mod_with_some_unsafe_things {
++    pub struct Safe;
++    pub struct Unsafe;
 +}
 +
 +use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
 +
 +// Shouldn't error
 +use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime;
 +use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing;
 +
 +fn main() {}
index 7a4bbdda1ab273879245443c17e6275c5a240737,0000000000000000000000000000000000000000..08bf58fec7c3eb0d21b18cb6c64334bfbcb88e53
mode 100644,000000..100644
--- /dev/null
@@@ -1,140 -1,0 +1,140 @@@
-     struct A {}
 +#![warn(clippy::unused_self)]
 +#![allow(clippy::boxed_local, clippy::fn_params_excessive_bools)]
 +
 +mod unused_self {
 +    use std::pin::Pin;
 +    use std::sync::{Arc, Mutex};
 +
-     struct A {}
++    struct A;
 +
 +    impl A {
 +        fn unused_self_move(self) {}
 +        fn unused_self_ref(&self) {}
 +        fn unused_self_mut_ref(&mut self) {}
 +        fn unused_self_pin_ref(self: Pin<&Self>) {}
 +        fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {}
 +        fn unused_self_pin_nested(self: Pin<Arc<Self>>) {}
 +        fn unused_self_box(self: Box<Self>) {}
 +        fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 {
 +            x + y
 +        }
 +        fn unused_self_class_method(&self) {
 +            Self::static_method();
 +        }
 +
 +        fn static_method() {}
 +    }
 +}
 +
 +mod unused_self_allow {
-     struct B {}
++    struct A;
 +
 +    impl A {
 +        // shouldn't trigger
 +        #[allow(clippy::unused_self)]
 +        fn unused_self_move(self) {}
 +    }
 +
-     struct C {}
++    struct B;
 +
 +    // shouldn't trigger
 +    #[allow(clippy::unused_self)]
 +    impl B {
 +        fn unused_self_move(self) {}
 +    }
 +
-     struct A {}
++    struct C;
 +
 +    #[allow(clippy::unused_self)]
 +    impl C {
 +        #[warn(clippy::unused_self)]
 +        fn some_fn((): ()) {}
 +
 +        // shouldn't trigger
 +        fn unused_self_move(self) {}
 +    }
 +}
 +
 +mod used_self {
 +    use std::pin::Pin;
 +
 +    struct A {
 +        x: u8,
 +    }
 +
 +    impl A {
 +        fn used_self_move(self) -> u8 {
 +            self.x
 +        }
 +        fn used_self_ref(&self) -> u8 {
 +            self.x
 +        }
 +        fn used_self_mut_ref(&mut self) {
 +            self.x += 1
 +        }
 +        fn used_self_pin_ref(self: Pin<&Self>) -> u8 {
 +            self.x
 +        }
 +        fn used_self_box(self: Box<Self>) -> u8 {
 +            self.x
 +        }
 +        fn used_self_with_other_unused_args(&self, x: u8, y: u8) -> u8 {
 +            self.x
 +        }
 +        fn used_in_nested_closure(&self) -> u8 {
 +            let mut a = || -> u8 { self.x };
 +            a()
 +        }
 +
 +        #[allow(clippy::collapsible_if)]
 +        fn used_self_method_nested_conditions(&self, a: bool, b: bool, c: bool, d: bool) {
 +            if a {
 +                if b {
 +                    if c {
 +                        if d {
 +                            self.used_self_ref();
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        fn foo(&self) -> u32 {
 +            let mut sum = 0u32;
 +            for i in 0..self.x {
 +                sum += i as u32;
 +            }
 +            sum
 +        }
 +
 +        fn bar(&mut self, x: u8) -> u32 {
 +            let mut y = 0u32;
 +            for i in 0..x {
 +                y += self.foo()
 +            }
 +            y
 +        }
 +    }
 +}
 +
 +mod not_applicable {
 +    use std::fmt;
 +
++    struct A;
 +
 +    impl fmt::Debug for A {
 +        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +            write!(f, "A")
 +        }
 +    }
 +
 +    impl A {
 +        fn method(x: u8, y: u8) {}
 +    }
 +
 +    trait B {
 +        fn method(&self) {}
 +    }
 +}
 +
 +fn main() {}
index 9d216f56ae60c66b3a22df7158c40a893f424e08,0000000000000000000000000000000000000000..3e62ffe74feddb270f358cc17785175353e34495
mode 100644,000000..100644
--- /dev/null
@@@ -1,544 -1,0 +1,544 @@@
-     struct Foo {}
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::use_self)]
 +#![allow(dead_code, unreachable_code)]
 +#![allow(
 +    clippy::should_implement_trait,
 +    clippy::upper_case_acronyms,
 +    clippy::from_over_into,
 +    clippy::self_named_constructors
 +)]
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +fn main() {}
 +
 +mod use_self {
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod better {
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod lifetimes {
 +    struct Foo<'a> {
 +        foo_str: &'a str,
 +    }
 +
 +    impl<'a> Foo<'a> {
 +        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
 +        // Foo<'b>`
 +        fn foo(s: &str) -> Foo {
 +            Foo { foo_str: s }
 +        }
 +        // cannot replace with `Self`, because that's `Foo<'a>`
 +        fn bar() -> Foo<'static> {
 +            Foo { foo_str: "foo" }
 +        }
 +
 +        // FIXME: the lint does not handle lifetimed struct
 +        // `Self` should be applicable here
 +        fn clone(&self) -> Foo<'a> {
 +            Foo { foo_str: self.foo_str }
 +        }
 +    }
 +}
 +
 +mod issue2894 {
 +    trait IntoBytes {
 +        fn to_bytes(self) -> Vec<u8>;
 +    }
 +
 +    // This should not be linted
 +    impl IntoBytes for u8 {
 +        fn to_bytes(self) -> Vec<u8> {
 +            vec![self]
 +        }
 +    }
 +}
 +
 +mod existential {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn bad(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +
 +        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +    }
 +}
 +
 +mod tuple_structs {
 +    pub struct TS(i32);
 +
 +    impl TS {
 +        pub fn ts() -> Self {
 +            Self(0)
 +        }
 +    }
 +}
 +
 +mod macros {
 +    macro_rules! use_self_expand {
 +        () => {
 +            fn new() -> Foo {
 +                Foo {}
 +            }
 +        };
 +    }
 +
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        use_self_expand!(); // Should not lint in local macros
 +    }
 +
 +    #[derive(StructAUseSelf)] // Should not lint in derives
 +    struct A;
 +}
 +
 +mod nesting {
-         pub struct A {}
++    struct Foo;
 +    impl Foo {
 +        fn foo() {
 +            #[allow(unused_imports)]
 +            use self::Foo; // Can't use Self here
 +            struct Bar {
 +                foo: Foo, // Foo != Self
 +            }
 +
 +            impl Bar {
 +                fn bar() -> Self {
 +                    Self { foo: Foo {} }
 +                }
 +            }
 +
 +            // Can't use Self here
 +            fn baz() -> Foo {
 +                Foo {}
 +            }
 +        }
 +
 +        // Should lint here
 +        fn baz() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    enum Enum {
 +        A,
 +        B(u64),
 +        C { field: bool },
 +    }
 +    impl Enum {
 +        fn method() {
 +            #[allow(unused_imports)]
 +            use self::Enum::*; // Issue 3425
 +            static STATIC: Enum = Enum::A; // Can't use Self as type
 +        }
 +
 +        fn method2() {
 +            let _ = Self::B(42);
 +            let _ = Self::C { field: true };
 +            let _ = Self::A;
 +        }
 +    }
 +}
 +
 +mod issue3410 {
 +
 +    struct A;
 +    struct B;
 +
 +    trait Trait<T> {
 +        fn a(v: T) -> Self;
 +    }
 +
 +    impl Trait<Vec<A>> for Vec<B> {
 +        fn a(_: Vec<A>) -> Self {
 +            unimplemented!()
 +        }
 +    }
 +
 +    impl<T> Trait<Vec<A>> for Vec<T>
 +    where
 +        T: Trait<B>,
 +    {
 +        fn a(v: Vec<A>) -> Self {
 +            <Vec<B>>::a(v).into_iter().map(Trait::a).collect()
 +        }
 +    }
 +}
 +
 +#[allow(clippy::no_effect, path_statements)]
 +mod rustfix {
 +    mod nested {
-     struct TestStruct {}
++        pub struct A;
 +    }
 +
 +    impl nested::A {
 +        const A: bool = true;
 +
 +        fn fun_1() {}
 +
 +        fn fun_2() {
 +            Self::fun_1();
 +            Self::A;
 +
 +            Self {};
 +        }
 +    }
 +}
 +
 +mod issue3567 {
-     struct S {}
++    struct TestStruct;
 +    impl TestStruct {
 +        fn from_something() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    trait Test {
 +        fn test() -> TestStruct;
 +    }
 +
 +    impl Test for TestStruct {
 +        fn test() -> TestStruct {
 +            Self::from_something()
 +        }
 +    }
 +}
 +
 +mod paths_created_by_lowering {
 +    use std::ops::Range;
 +
-     struct Foo {}
++    struct S;
 +
 +    impl S {
 +        const A: usize = 0;
 +        const B: usize = 1;
 +
 +        async fn g() -> Self {
 +            Self {}
 +        }
 +
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[Self::A..Self::B]
 +        }
 +    }
 +
 +    trait T {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
 +    }
 +
 +    impl T for Range<u8> {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[0..1]
 +        }
 +    }
 +}
 +
 +// reused from #1997
 +mod generics {
 +    struct Foo<T> {
 +        value: T,
 +    }
 +
 +    impl<T> Foo<T> {
 +        // `Self` is applicable here
 +        fn foo(value: T) -> Self {
 +            Self { value }
 +        }
 +
 +        // `Cannot` use `Self` as a return type as the generic types are different
 +        fn bar(value: i32) -> Foo<i32> {
 +            Foo { value }
 +        }
 +    }
 +}
 +
 +mod issue4140 {
 +    pub struct Error<From, To> {
 +        _from: From,
 +        _too: To,
 +    }
 +
 +    pub trait From<T> {
 +        type From;
 +        type To;
 +
 +        fn from(value: T) -> Self;
 +    }
 +
 +    pub trait TryFrom<T>
 +    where
 +        Self: Sized,
 +    {
 +        type From;
 +        type To;
 +
 +        fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>;
 +    }
 +
 +    // FIXME: Suggested fix results in infinite recursion.
 +    // impl<F, T> TryFrom<F> for T
 +    // where
 +    //     T: From<F>,
 +    // {
 +    //     type From = Self::From;
 +    //     type To = Self::To;
 +
 +    //     fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> {
 +    //         Ok(From::from(value))
 +    //     }
 +    // }
 +
 +    impl From<bool> for i64 {
 +        type From = bool;
 +        type To = Self;
 +
 +        fn from(value: bool) -> Self {
 +            if value { 100 } else { 0 }
 +        }
 +    }
 +}
 +
 +mod issue2843 {
 +    trait Foo {
 +        type Bar;
 +    }
 +
 +    impl Foo for usize {
 +        type Bar = u8;
 +    }
 +
 +    impl<T: Foo> Foo for Option<T> {
 +        type Bar = Option<T::Bar>;
 +    }
 +}
 +
 +mod issue3859 {
 +    pub struct Foo;
 +    pub struct Bar([usize; 3]);
 +
 +    impl Foo {
 +        pub const BAR: usize = 3;
 +
 +        pub fn foo() {
 +            const _X: usize = Foo::BAR;
 +            // const _Y: usize = Self::BAR;
 +        }
 +    }
 +}
 +
 +mod issue4305 {
 +    trait Foo: 'static {}
 +
 +    struct Bar;
 +
 +    impl Foo for Bar {}
 +
 +    impl<T: Foo> From<T> for Box<dyn Foo> {
 +        fn from(t: T) -> Self {
 +            Box::new(t)
 +        }
 +    }
 +}
 +
 +mod lint_at_item_level {
-     struct Foo {}
++    struct Foo;
 +
 +    #[allow(clippy::use_self)]
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    #[allow(clippy::use_self)]
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod lint_at_impl_item_level {
-         pub struct B {}
-         pub struct C {}
++    struct Foo;
 +
 +    impl Foo {
 +        #[allow(clippy::use_self)]
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        #[allow(clippy::use_self)]
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod issue4734 {
 +    #[repr(C, packed)]
 +    pub struct X {
 +        pub x: u32,
 +    }
 +
 +    impl From<X> for u32 {
 +        fn from(c: X) -> Self {
 +            unsafe { core::mem::transmute(c) }
 +        }
 +    }
 +}
 +
 +mod nested_paths {
 +    use std::convert::Into;
 +    mod submod {
++        pub struct B;
++        pub struct C;
 +
 +        impl Into<C> for B {
 +            fn into(self) -> C {
 +                C {}
 +            }
 +        }
 +    }
 +
 +    struct A<T> {
 +        t: T,
 +    }
 +
 +    impl<T> A<T> {
 +        fn new<V: Into<T>>(v: V) -> Self {
 +            Self { t: Into::into(v) }
 +        }
 +    }
 +
 +    impl A<submod::C> {
 +        fn test() -> Self {
 +            Self::new::<submod::B>(submod::B {})
 +        }
 +    }
 +}
 +
 +mod issue6818 {
 +    #[derive(serde::Deserialize)]
 +    struct A {
 +        a: i32,
 +    }
 +}
 +
 +mod issue7206 {
 +    struct MyStruct<const C: char>;
 +    impl From<MyStruct<'a'>> for MyStruct<'b'> {
 +        fn from(_s: MyStruct<'a'>) -> Self {
 +            Self
 +        }
 +    }
 +
 +    // keep linting non-`Const` generic args
 +    struct S<'a> {
 +        inner: &'a str,
 +    }
 +
 +    struct S2<T> {
 +        inner: T,
 +    }
 +
 +    impl<T> S2<T> {
 +        fn new() -> Self {
 +            unimplemented!();
 +        }
 +    }
 +
 +    impl<'a> S2<S<'a>> {
 +        fn new_again() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod self_is_ty_param {
 +    trait Trait {
 +        type Type;
 +        type Hi;
 +
 +        fn test();
 +    }
 +
 +    impl<I> Trait for I
 +    where
 +        I: Iterator,
 +        I::Item: Trait, // changing this to Self would require <Self as Iterator>
 +    {
 +        type Type = I;
 +        type Hi = I::Item;
 +
 +        fn test() {
 +            let _: I::Item;
 +            let _: I; // this could lint, but is questionable
 +        }
 +    }
 +}
 +
 +mod use_self_in_pat {
 +    enum Foo {
 +        Bar,
 +        Baz,
 +    }
 +
 +    impl Foo {
 +        fn do_stuff(self) {
 +            match self {
 +                Self::Bar => unimplemented!(),
 +                Self::Baz => unimplemented!(),
 +            }
 +            match Some(1) {
 +                Some(_) => unimplemented!(),
 +                None => unimplemented!(),
 +            }
 +            if let Self::Bar = self {
 +                unimplemented!()
 +            }
 +        }
 +    }
 +}
index 5f604fe25e416d93e2fafbf4883b92be539ca0ec,0000000000000000000000000000000000000000..da2faddee12a71327de345e5c7460659853690dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,544 -1,0 +1,544 @@@
-     struct Foo {}
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::use_self)]
 +#![allow(dead_code, unreachable_code)]
 +#![allow(
 +    clippy::should_implement_trait,
 +    clippy::upper_case_acronyms,
 +    clippy::from_over_into,
 +    clippy::self_named_constructors
 +)]
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +fn main() {}
 +
 +mod use_self {
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +        fn test() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod better {
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod lifetimes {
 +    struct Foo<'a> {
 +        foo_str: &'a str,
 +    }
 +
 +    impl<'a> Foo<'a> {
 +        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
 +        // Foo<'b>`
 +        fn foo(s: &str) -> Foo {
 +            Foo { foo_str: s }
 +        }
 +        // cannot replace with `Self`, because that's `Foo<'a>`
 +        fn bar() -> Foo<'static> {
 +            Foo { foo_str: "foo" }
 +        }
 +
 +        // FIXME: the lint does not handle lifetimed struct
 +        // `Self` should be applicable here
 +        fn clone(&self) -> Foo<'a> {
 +            Foo { foo_str: self.foo_str }
 +        }
 +    }
 +}
 +
 +mod issue2894 {
 +    trait IntoBytes {
 +        fn to_bytes(self) -> Vec<u8>;
 +    }
 +
 +    // This should not be linted
 +    impl IntoBytes for u8 {
 +        fn to_bytes(self) -> Vec<u8> {
 +            vec![self]
 +        }
 +    }
 +}
 +
 +mod existential {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
 +            foos.iter()
 +        }
 +
 +        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +    }
 +}
 +
 +mod tuple_structs {
 +    pub struct TS(i32);
 +
 +    impl TS {
 +        pub fn ts() -> Self {
 +            TS(0)
 +        }
 +    }
 +}
 +
 +mod macros {
 +    macro_rules! use_self_expand {
 +        () => {
 +            fn new() -> Foo {
 +                Foo {}
 +            }
 +        };
 +    }
 +
-     struct Foo {}
++    struct Foo;
 +
 +    impl Foo {
 +        use_self_expand!(); // Should not lint in local macros
 +    }
 +
 +    #[derive(StructAUseSelf)] // Should not lint in derives
 +    struct A;
 +}
 +
 +mod nesting {
-         pub struct A {}
++    struct Foo;
 +    impl Foo {
 +        fn foo() {
 +            #[allow(unused_imports)]
 +            use self::Foo; // Can't use Self here
 +            struct Bar {
 +                foo: Foo, // Foo != Self
 +            }
 +
 +            impl Bar {
 +                fn bar() -> Bar {
 +                    Bar { foo: Foo {} }
 +                }
 +            }
 +
 +            // Can't use Self here
 +            fn baz() -> Foo {
 +                Foo {}
 +            }
 +        }
 +
 +        // Should lint here
 +        fn baz() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    enum Enum {
 +        A,
 +        B(u64),
 +        C { field: bool },
 +    }
 +    impl Enum {
 +        fn method() {
 +            #[allow(unused_imports)]
 +            use self::Enum::*; // Issue 3425
 +            static STATIC: Enum = Enum::A; // Can't use Self as type
 +        }
 +
 +        fn method2() {
 +            let _ = Enum::B(42);
 +            let _ = Enum::C { field: true };
 +            let _ = Enum::A;
 +        }
 +    }
 +}
 +
 +mod issue3410 {
 +
 +    struct A;
 +    struct B;
 +
 +    trait Trait<T> {
 +        fn a(v: T) -> Self;
 +    }
 +
 +    impl Trait<Vec<A>> for Vec<B> {
 +        fn a(_: Vec<A>) -> Self {
 +            unimplemented!()
 +        }
 +    }
 +
 +    impl<T> Trait<Vec<A>> for Vec<T>
 +    where
 +        T: Trait<B>,
 +    {
 +        fn a(v: Vec<A>) -> Self {
 +            <Vec<B>>::a(v).into_iter().map(Trait::a).collect()
 +        }
 +    }
 +}
 +
 +#[allow(clippy::no_effect, path_statements)]
 +mod rustfix {
 +    mod nested {
-     struct TestStruct {}
++        pub struct A;
 +    }
 +
 +    impl nested::A {
 +        const A: bool = true;
 +
 +        fn fun_1() {}
 +
 +        fn fun_2() {
 +            nested::A::fun_1();
 +            nested::A::A;
 +
 +            nested::A {};
 +        }
 +    }
 +}
 +
 +mod issue3567 {
-     struct S {}
++    struct TestStruct;
 +    impl TestStruct {
 +        fn from_something() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    trait Test {
 +        fn test() -> TestStruct;
 +    }
 +
 +    impl Test for TestStruct {
 +        fn test() -> TestStruct {
 +            TestStruct::from_something()
 +        }
 +    }
 +}
 +
 +mod paths_created_by_lowering {
 +    use std::ops::Range;
 +
-     struct Foo {}
++    struct S;
 +
 +    impl S {
 +        const A: usize = 0;
 +        const B: usize = 1;
 +
 +        async fn g() -> S {
 +            S {}
 +        }
 +
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[S::A..S::B]
 +        }
 +    }
 +
 +    trait T {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
 +    }
 +
 +    impl T for Range<u8> {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[0..1]
 +        }
 +    }
 +}
 +
 +// reused from #1997
 +mod generics {
 +    struct Foo<T> {
 +        value: T,
 +    }
 +
 +    impl<T> Foo<T> {
 +        // `Self` is applicable here
 +        fn foo(value: T) -> Foo<T> {
 +            Foo::<T> { value }
 +        }
 +
 +        // `Cannot` use `Self` as a return type as the generic types are different
 +        fn bar(value: i32) -> Foo<i32> {
 +            Foo { value }
 +        }
 +    }
 +}
 +
 +mod issue4140 {
 +    pub struct Error<From, To> {
 +        _from: From,
 +        _too: To,
 +    }
 +
 +    pub trait From<T> {
 +        type From;
 +        type To;
 +
 +        fn from(value: T) -> Self;
 +    }
 +
 +    pub trait TryFrom<T>
 +    where
 +        Self: Sized,
 +    {
 +        type From;
 +        type To;
 +
 +        fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>;
 +    }
 +
 +    // FIXME: Suggested fix results in infinite recursion.
 +    // impl<F, T> TryFrom<F> for T
 +    // where
 +    //     T: From<F>,
 +    // {
 +    //     type From = Self::From;
 +    //     type To = Self::To;
 +
 +    //     fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> {
 +    //         Ok(From::from(value))
 +    //     }
 +    // }
 +
 +    impl From<bool> for i64 {
 +        type From = bool;
 +        type To = Self;
 +
 +        fn from(value: bool) -> Self {
 +            if value { 100 } else { 0 }
 +        }
 +    }
 +}
 +
 +mod issue2843 {
 +    trait Foo {
 +        type Bar;
 +    }
 +
 +    impl Foo for usize {
 +        type Bar = u8;
 +    }
 +
 +    impl<T: Foo> Foo for Option<T> {
 +        type Bar = Option<T::Bar>;
 +    }
 +}
 +
 +mod issue3859 {
 +    pub struct Foo;
 +    pub struct Bar([usize; 3]);
 +
 +    impl Foo {
 +        pub const BAR: usize = 3;
 +
 +        pub fn foo() {
 +            const _X: usize = Foo::BAR;
 +            // const _Y: usize = Self::BAR;
 +        }
 +    }
 +}
 +
 +mod issue4305 {
 +    trait Foo: 'static {}
 +
 +    struct Bar;
 +
 +    impl Foo for Bar {}
 +
 +    impl<T: Foo> From<T> for Box<dyn Foo> {
 +        fn from(t: T) -> Self {
 +            Box::new(t)
 +        }
 +    }
 +}
 +
 +mod lint_at_item_level {
-     struct Foo {}
++    struct Foo;
 +
 +    #[allow(clippy::use_self)]
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    #[allow(clippy::use_self)]
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod lint_at_impl_item_level {
-         pub struct B {}
-         pub struct C {}
++    struct Foo;
 +
 +    impl Foo {
 +        #[allow(clippy::use_self)]
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        #[allow(clippy::use_self)]
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod issue4734 {
 +    #[repr(C, packed)]
 +    pub struct X {
 +        pub x: u32,
 +    }
 +
 +    impl From<X> for u32 {
 +        fn from(c: X) -> Self {
 +            unsafe { core::mem::transmute(c) }
 +        }
 +    }
 +}
 +
 +mod nested_paths {
 +    use std::convert::Into;
 +    mod submod {
++        pub struct B;
++        pub struct C;
 +
 +        impl Into<C> for B {
 +            fn into(self) -> C {
 +                C {}
 +            }
 +        }
 +    }
 +
 +    struct A<T> {
 +        t: T,
 +    }
 +
 +    impl<T> A<T> {
 +        fn new<V: Into<T>>(v: V) -> Self {
 +            Self { t: Into::into(v) }
 +        }
 +    }
 +
 +    impl A<submod::C> {
 +        fn test() -> Self {
 +            A::new::<submod::B>(submod::B {})
 +        }
 +    }
 +}
 +
 +mod issue6818 {
 +    #[derive(serde::Deserialize)]
 +    struct A {
 +        a: i32,
 +    }
 +}
 +
 +mod issue7206 {
 +    struct MyStruct<const C: char>;
 +    impl From<MyStruct<'a'>> for MyStruct<'b'> {
 +        fn from(_s: MyStruct<'a'>) -> Self {
 +            Self
 +        }
 +    }
 +
 +    // keep linting non-`Const` generic args
 +    struct S<'a> {
 +        inner: &'a str,
 +    }
 +
 +    struct S2<T> {
 +        inner: T,
 +    }
 +
 +    impl<T> S2<T> {
 +        fn new() -> Self {
 +            unimplemented!();
 +        }
 +    }
 +
 +    impl<'a> S2<S<'a>> {
 +        fn new_again() -> Self {
 +            S2::new()
 +        }
 +    }
 +}
 +
 +mod self_is_ty_param {
 +    trait Trait {
 +        type Type;
 +        type Hi;
 +
 +        fn test();
 +    }
 +
 +    impl<I> Trait for I
 +    where
 +        I: Iterator,
 +        I::Item: Trait, // changing this to Self would require <Self as Iterator>
 +    {
 +        type Type = I;
 +        type Hi = I::Item;
 +
 +        fn test() {
 +            let _: I::Item;
 +            let _: I; // this could lint, but is questionable
 +        }
 +    }
 +}
 +
 +mod use_self_in_pat {
 +    enum Foo {
 +        Bar,
 +        Baz,
 +    }
 +
 +    impl Foo {
 +        fn do_stuff(self) {
 +            match self {
 +                Foo::Bar => unimplemented!(),
 +                Foo::Baz => unimplemented!(),
 +            }
 +            match Some(1) {
 +                Some(_) => unimplemented!(),
 +                None => unimplemented!(),
 +            }
 +            if let Foo::Bar = self {
 +                unimplemented!()
 +            }
 +        }
 +    }
 +}
index a5fcde768f18344ed7684116e0ce5f9aeeb52ee5,0000000000000000000000000000000000000000..ce58a80347b558ef7a46b48b2883def9f0455f71
mode 100644,000000..100644
--- /dev/null
@@@ -1,69 -1,0 +1,69 @@@
-         pub struct C {}
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::useless_attribute)]
 +#![warn(unreachable_pub)]
 +#![feature(rustc_private)]
 +
 +#![allow(dead_code)]
 +#![cfg_attr(feature = "cargo-clippy", allow(dead_code))]
 +#[rustfmt::skip]
 +#[allow(unused_imports)]
 +#[allow(unused_extern_crates)]
 +#[macro_use]
 +extern crate rustc_middle;
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +// don't lint on unused_import for `use` items
 +#[allow(unused_imports)]
 +use std::collections;
 +
 +// don't lint on unused for `use` items
 +#[allow(unused)]
 +use std::option;
 +
 +// don't lint on deprecated for `use` items
 +mod foo {
 +    #[deprecated]
 +    pub struct Bar;
 +}
 +#[allow(deprecated)]
 +pub use foo::Bar;
 +
 +// This should not trigger the lint. There's lint level definitions inside the external derive
 +// that would trigger the useless_attribute lint.
 +#[derive(DeriveSomething)]
 +struct Baz;
 +
 +// don't lint on unreachable_pub for `use` items
 +mod a {
 +    mod b {
 +        #[allow(dead_code)]
 +        #[allow(unreachable_pub)]
++        pub struct C;
 +    }
 +
 +    #[allow(unreachable_pub)]
 +    pub use self::b::C;
 +}
 +
 +// don't lint on clippy::wildcard_imports for `use` items
 +#[allow(clippy::wildcard_imports)]
 +pub use std::io::prelude::*;
 +
 +// don't lint on clippy::enum_glob_use for `use` items
 +#[allow(clippy::enum_glob_use)]
 +pub use std::cmp::Ordering::*;
 +
 +fn test_indented_attr() {
 +    #![allow(clippy::almost_swapped)]
 +    use std::collections::HashSet;
 +
 +    let _ = HashSet::<u32>::default();
 +}
 +
 +fn main() {
 +    test_indented_attr();
 +}
index 0396d39e3d54eff2151a4d43964c70cac8d86051,0000000000000000000000000000000000000000..c82bb9ba07fd731efb14a91a954fb3a132cc6423
mode 100644,000000..100644
--- /dev/null
@@@ -1,69 -1,0 +1,69 @@@
-         pub struct C {}
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::useless_attribute)]
 +#![warn(unreachable_pub)]
 +#![feature(rustc_private)]
 +
 +#[allow(dead_code)]
 +#[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
 +#[rustfmt::skip]
 +#[allow(unused_imports)]
 +#[allow(unused_extern_crates)]
 +#[macro_use]
 +extern crate rustc_middle;
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +// don't lint on unused_import for `use` items
 +#[allow(unused_imports)]
 +use std::collections;
 +
 +// don't lint on unused for `use` items
 +#[allow(unused)]
 +use std::option;
 +
 +// don't lint on deprecated for `use` items
 +mod foo {
 +    #[deprecated]
 +    pub struct Bar;
 +}
 +#[allow(deprecated)]
 +pub use foo::Bar;
 +
 +// This should not trigger the lint. There's lint level definitions inside the external derive
 +// that would trigger the useless_attribute lint.
 +#[derive(DeriveSomething)]
 +struct Baz;
 +
 +// don't lint on unreachable_pub for `use` items
 +mod a {
 +    mod b {
 +        #[allow(dead_code)]
 +        #[allow(unreachable_pub)]
++        pub struct C;
 +    }
 +
 +    #[allow(unreachable_pub)]
 +    pub use self::b::C;
 +}
 +
 +// don't lint on clippy::wildcard_imports for `use` items
 +#[allow(clippy::wildcard_imports)]
 +pub use std::io::prelude::*;
 +
 +// don't lint on clippy::enum_glob_use for `use` items
 +#[allow(clippy::enum_glob_use)]
 +pub use std::cmp::Ordering::*;
 +
 +fn test_indented_attr() {
 +    #[allow(clippy::almost_swapped)]
 +    use std::collections::HashSet;
 +
 +    let _ = HashSet::<u32>::default();
 +}
 +
 +fn main() {
 +    test_indented_attr();
 +}
index 77102b8cac0c977e9621dc9bcc1bf1c6bcb5c11d,0000000000000000000000000000000000000000..38498ebdcf2c1ed49f0f22ee3a2be6a2c29d078e
mode 100644,000000..100644
--- /dev/null
@@@ -1,91 -1,0 +1,89 @@@
-     let clippy_meta = cargo_metadata::MetadataCommand::new()
-         .no_deps()
-         .exec()
-         .expect("could not obtain cargo metadata");
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +#![allow(clippy::single_match_else)]
 +
 +use rustc_tools_util::VersionInfo;
++use std::fs;
 +
 +#[test]
 +fn check_that_clippy_lints_and_clippy_utils_have_the_same_version_as_clippy() {
++    fn read_version(path: &str) -> String {
++        let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{}`: {:?}", path, e));
++        contents
++            .lines()
++            .filter_map(|l| l.split_once('='))
++            .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))
++            .unwrap_or_else(|| panic!("error finding version in `{}`", path))
++            .to_string()
++    }
++
 +    // do not run this test inside the upstream rustc repo:
 +    // https://github.com/rust-lang/rust-clippy/issues/6683
 +    if option_env!("RUSTC_TEST_SUITE").is_some() {
 +        return;
 +    }
 +
-     for krate in &["clippy_lints", "clippy_utils"] {
-         let krate_meta = cargo_metadata::MetadataCommand::new()
-             .current_dir(std::env::current_dir().unwrap().join(krate))
-             .no_deps()
-             .exec()
-             .expect("could not obtain cargo metadata");
-         assert_eq!(krate_meta.packages[0].version, clippy_meta.packages[0].version);
-         for package in &clippy_meta.packages[0].dependencies {
-             if package.name == *krate {
-                 assert!(package.req.matches(&krate_meta.packages[0].version));
-                 break;
-             }
-         }
-     }
++    let clippy_version = read_version("Cargo.toml");
++    let clippy_lints_version = read_version("clippy_lints/Cargo.toml");
++    let clippy_utils_version = read_version("clippy_utils/Cargo.toml");
 +
++    assert_eq!(clippy_version, clippy_lints_version);
++    assert_eq!(clippy_version, clippy_utils_version);
 +}
 +
 +#[test]
 +fn check_that_clippy_has_the_same_major_version_as_rustc() {
 +    // do not run this test inside the upstream rustc repo:
 +    // https://github.com/rust-lang/rust-clippy/issues/6683
 +    if option_env!("RUSTC_TEST_SUITE").is_some() {
 +        return;
 +    }
 +
 +    let clippy_version = rustc_tools_util::get_version_info!();
 +    let clippy_major = clippy_version.major;
 +    let clippy_minor = clippy_version.minor;
 +    let clippy_patch = clippy_version.patch;
 +
 +    // get the rustc version either from the rustc installed with the toolchain file or from
 +    // `RUSTC_REAL` if Clippy is build in the Rust repo with `./x.py`.
 +    let rustc = std::env::var("RUSTC_REAL").unwrap_or_else(|_| "rustc".to_string());
 +    let rustc_version = String::from_utf8(
 +        std::process::Command::new(&rustc)
 +            .arg("--version")
 +            .output()
 +            .expect("failed to run `rustc --version`")
 +            .stdout,
 +    )
 +    .unwrap();
 +    // extract "1 XX 0" from "rustc 1.XX.0-nightly (<commit> <date>)"
 +    let vsplit: Vec<&str> = rustc_version
 +        .split(' ')
 +        .nth(1)
 +        .unwrap()
 +        .split('-')
 +        .next()
 +        .unwrap()
 +        .split('.')
 +        .collect();
 +    match vsplit.as_slice() {
 +        [rustc_major, rustc_minor, _rustc_patch] => {
 +            // clippy 0.1.XX should correspond to rustc 1.XX.0
 +            assert_eq!(clippy_major, 0); // this will probably stay the same for a long time
 +            assert_eq!(
 +                clippy_minor.to_string(),
 +                *rustc_major,
 +                "clippy minor version does not equal rustc major version"
 +            );
 +            assert_eq!(
 +                clippy_patch.to_string(),
 +                *rustc_minor,
 +                "clippy patch version does not equal rustc minor version"
 +            );
 +            // do not check rustc_patch because when a stable-patch-release is made (like 1.50.2),
 +            // we don't want our tests failing suddenly
 +        },
 +        _ => {
 +            panic!("Failed to parse rustc version: {:?}", vsplit);
 +        },
 +    };
 +}