]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '3e4179766bcecd712824da04356621b8df012ea4' into sync-from-clippy
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 3 Feb 2021 04:43:30 +0000 (20:43 -0800)
committerManish Goregaokar <manishsmail@gmail.com>
Wed, 3 Feb 2021 04:43:30 +0000 (20:43 -0800)
35 files changed:
1  2 
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/clippy_dev/src/bless.rs
src/tools/clippy/clippy_dev/src/fmt.rs
src/tools/clippy/clippy_dev/src/lib.rs
src/tools/clippy/clippy_dev/src/ra_setup.rs
src/tools/clippy/clippy_dev/src/serve.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/excessive_bools.rs
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/clippy/clippy_lints/src/utils/diagnostics.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/mod.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/doc/adding_lints.md
src/tools/clippy/doc/basics.md
src/tools/clippy/mini-macro/src/lib.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/ui/doc_panics.rs
src/tools/clippy/tests/ui/doc_panics.stderr
src/tools/clippy/tests/ui/exhaustive_items.fixed
src/tools/clippy/tests/ui/exhaustive_items.rs
src/tools/clippy/tests/ui/exhaustive_items.stderr
src/tools/clippy/tests/ui/let_and_return.rs
src/tools/clippy/tests/ui/let_and_return.stderr
src/tools/clippy/tests/ui/match_overlapping_arm.rs
src/tools/clippy/tests/ui/match_overlapping_arm.stderr
src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr

index dadb6832d1fd7c2587a898e9bb6483d5909e77b3,0000000000000000000000000000000000000000..c1032204a22cb8b618f4609fdd713acd64c94ec8
mode 100644,000000..100644
--- /dev/null
@@@ -1,2316 -1,0 +1,2317 @@@
 +# 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
 +
 +[4911ab1...master](https://github.com/rust-lang/rust-clippy/compare/4911ab1...master)
 +
 +## Rust 1.50
 +
 +Current beta, release 2021-02-11
 +
 +[b20d4c1...4911ab1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4911ab1)
 +
 +### 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 `panic_fmt`
 +  [#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)
 +
 +
 +### 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
 +
 +Current stable, released 2020-12-31
 +
 +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 +
 +### New Lints
 +
 +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
 +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
 +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
 +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
 +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
 +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
 +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
 +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
 +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
 +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
 +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
 +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
 +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
 +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
 +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
 +
 +### Moves and Deprecations
 +
 +* Rename `single_char_push_str` to [`single_char_add_str`]
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* Rename `zero_width_space` to [`invisible_characters`]
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* Deprecate [`drop_bounds`] (uplifted)
 +  [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
 +* Move [`string_lit_as_bytes`] to `nursery`
 +  [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
 +* Move [`rc_buffer`] to `restriction`
 +  [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
 +
 +### Enhancements
 +
 +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
 +  reliable suggestion)
 +  [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
 +* [`single_char_add_str`]: Also lint on `String::insert_str`
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* [`eq_op`]: Also lint on the `assert_*!` macro family
 +  [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
 +* [`items_after_statements`]: Also lint in local macro expansions
 +  [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
 +* [`unnecessary_cast`]: Also lint casts on integer and float literals
 +  [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
 +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
 +  [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
 +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
 +  [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
 +* [`integer_arithmetic`]: Better handle `/` an `%` operators
 +  [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
 +
 +### False Positive Fixes
 +
 +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
 +  lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
 +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
 +  is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
 +* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
 +  [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
 +* [`needless_range_loop`]: No longer lints, when the iterable is used in the
 +  range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
 +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
 +  [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
 +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
 +  float (e.g. `713.32_64`)
 +  [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
 +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
 +  [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
 +* [`boxed_local`]: No longer lints on `extern fn` arguments
 +  [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
 +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
 +  clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
 +  [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
 +* [`needless_arbitrary_self_type`]: Correctly handle expanded code
 +  [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
 +* [`useless_format`]: Preserve raw strings in suggestion
 +  [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
 +* [`empty_loop`]: Suggest alternatives
 +  [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`borrowed_box`]: Correctly add parentheses in suggestion
 +  [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
 +* [`unused_unit`]: Improve suggestion formatting
 +  [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
 +
 +### Documentation Improvements
 +
 +* Some doc improvements:
 +    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
 +    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`doc_markdown`]: Document problematic link text style
 +  [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 +
 +## Rust 1.48
 +
 +Released 2020-11-19
 +
 +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 +
 +### New lints
 +
 +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
 +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
 +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
 +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 +* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
 +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`verbose_bit_mask`] to pedantic
 +  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
 +
 +### Enhancements
 +
 +* Extend [`precedence`] to handle chains of methods combined with unary negation
 +  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
 +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
 +  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
 +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
 +  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
 +* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
 +  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
 +* Avoid [`redundant_pattern_matching`] triggering in macros
 +  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
 +* [`option_if_let_else`]: distinguish pure from impure `else` expressions
 +  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
 +* [`needless_doctest_main`]: parse doctests instead of using textual search
 +  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
 +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
 +  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
 +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
 +  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
 +
 +### False Positive Fixes
 +
 +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
 +  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
 +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
 +  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
 +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
 +  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
 +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
 +  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
 +* [`doc_markdown`]: allow using "GraphQL" without backticks
 +  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
 +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
 +  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
 +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
 +  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
 +* [`should_implement_trait`]: ignore methods with lifetime parameters
 +  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
 +* [`needless_return`]: avoid linting if a temporary borrows a local variable
 +  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
 +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
 +  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
 +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
 +  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
 +  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
 +  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
 +* [`useless_conversion`]: show the type in the error message
 +  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
 +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
 +  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
 +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
 +  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
 +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
 +  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
 +* [`collapsible_if`]: don't use expanded code in the suggestion
 +  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
 +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
 +  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
 +* [`unit_arg`]: improve the readability of the suggestion
 +  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
 +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
 +  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
 +* Show line count and max lines in [`too_many_lines`] lint message
 +  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
 +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
 +  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
 +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
 +  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
 +* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
 +  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
 +* Make lint messages adhere to rustc dev guide conventions
 +  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`repeat_once`]
 +  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
 +
 +### Documentation Improvements
 +
 +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
 +  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
 +* [`unnecessary_mut_passed`]: fix typo
 +  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
 +* Add example of false positive to [`ptr_arg`] docs.
 +  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
 +* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
 +  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 +
 +## Rust 1.47
 +
 +Released 2020-10-08
 +
 +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 +
 +### New lints
 +
 +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
 +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
 +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
 +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
 +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
 +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
 +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
 +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
 +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
 +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
 +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
 +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`regex_macro`] lint
 +  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
 +* Move [`range_minus_one`] to `pedantic`
 +  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
 +
 +### Enhancements
 +
 +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
 +  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
 +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
 +  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
 +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
 +  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
 +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
 +  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
 +* Make it possible to allow [`unsafe_derive_deserialize`]
 +  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
 +* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
 +  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
 +* Make [`clone_on_copy`] suggestion machine applicable
 +  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
 +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +
 +### False Positive Fixes
 +
 +* Avoid triggering [`or_fun_call`] with const fns that take no arguments
 +  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
 +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
 +  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
 +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
 +  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
 +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
 +  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
 +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
 +  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
 +* Avoid linting if key borrows in [`unnecessary_sort_by`]
 +  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
 +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
 +  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
 +* Take input lifetimes into account in `manual_async_fn`
 +  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
 +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
 +  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
 +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
 +  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
 +  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
 +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
 +  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
 +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
 +  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
 +* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
 +  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
 +* Add suggestion for [`iter_skip_next`]
 +  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
 +* Improve [`collapsible_if`] fix suggestion
 +  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused by [`needless_collect`]
 +  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
 +* Fix ICE caused by [`unnested_or_patterns`]
 +  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
 +
 +### Documentation Improvements
 +
 +* Fix grammar of [`await_holding_lock`] documentation
 +  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
 +
 +### Others
 +
 +* Make lints adhere to the rustc dev guide
 +  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 +
 +## Rust 1.46
 +
 +Released 2020-08-27
 +
 +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 +
 +### New lints
 +
 +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
 +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
 +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
 +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
 +
 +### Moves and Deprecations
 +
 +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
 +
 +### Enhancements
 +
 +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
 +
 +### False Positive Fixes
 +
 +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
 +  [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
 +* [`let_and_return`]: Don't lint if a temporary borrow is involved
 +  [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
 +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
 +  [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 +* [`if_same_then_else`]: Don't assume multiplication is always commutative
 +  [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
 +* [`blacklisted_name`]: Remove `bar` from the default configuration
 +  [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
 +  [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
 +  [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
 +* Add auto applicable suggestion to [`macro_use_imports`]
 +  [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
 +
 +### ICE Fixes
 +
 +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
 +
 +### Documentation Improvements
 +
 +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
 +
 +### Others
 +
 +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
 +  into `rustc` and passes all the given arguments to `rustc`. This is especially
 +  useful for tools that need the `rustc` version Clippy was compiled with,
 +  instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
 +  print the output of `rustc --version`.
 +  [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
 +* New issue templates now make it easier to complain if Clippy is too annoying
 +  or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
 +
 +## Rust 1.45
 +
 +Released 2020-07-16
 +
 +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 +
 +### New lints
 +
 +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
 +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
 +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
 +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
 +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
 +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
 +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
 +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
 +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
 +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
 +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
 +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
 +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
 +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +
 +### Enhancements
 +
 +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
 +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
 +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
 +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
 +
 +### False Positive Fixes
 +
 +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
 +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
 +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
 +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
 +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
 +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
 +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
 +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
 +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
 +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
 +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
 +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
 +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
 +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
 +
 +### Suggestion Improvements
 +
 +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
 +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
 +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
 +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
 +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
 +
 +### Documentation
 +
 +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
 +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 +
 +## Rust 1.44
 +
 +Released 2020-06-04
 +
 +[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 +
 +### New lints
 +
 +* [`explicit_deref_methods`] [#5226](https://github.com/rust-lang/rust-clippy/pull/5226)
 +* [`implicit_saturating_sub`] [#5427](https://github.com/rust-lang/rust-clippy/pull/5427)
 +* [`macro_use_imports`] [#5230](https://github.com/rust-lang/rust-clippy/pull/5230)
 +* [`verbose_file_reads`] [#5272](https://github.com/rust-lang/rust-clippy/pull/5272)
 +* [`future_not_send`] [#5423](https://github.com/rust-lang/rust-clippy/pull/5423)
 +* [`redundant_pub_crate`] [#5319](https://github.com/rust-lang/rust-clippy/pull/5319)
 +* [`large_const_arrays`] [#5248](https://github.com/rust-lang/rust-clippy/pull/5248)
 +* [`result_map_or_into_option`] [#5415](https://github.com/rust-lang/rust-clippy/pull/5415)
 +* [`redundant_allocation`] [#5349](https://github.com/rust-lang/rust-clippy/pull/5349)
 +* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
 +* Move [`cognitive_complexity`] to nursery [#5428](https://github.com/rust-lang/rust-clippy/pull/5428)
 +* Move [`useless_transmute`] to nursery [#5364](https://github.com/rust-lang/rust-clippy/pull/5364)
 +* Downgrade [`inefficient_to_string`] to pedantic [#5412](https://github.com/rust-lang/rust-clippy/pull/5412)
 +* Downgrade [`option_option`] to pedantic [#5401](https://github.com/rust-lang/rust-clippy/pull/5401)
 +* Downgrade [`unreadable_literal`] to pedantic [#5419](https://github.com/rust-lang/rust-clippy/pull/5419)
 +* Downgrade [`let_unit_value`] to pedantic [#5409](https://github.com/rust-lang/rust-clippy/pull/5409)
 +* Downgrade [`trivially_copy_pass_by_ref`] to pedantic [#5410](https://github.com/rust-lang/rust-clippy/pull/5410)
 +* Downgrade [`implicit_hasher`] to pedantic [#5411](https://github.com/rust-lang/rust-clippy/pull/5411)
 +
 +### Enhancements
 +
 +* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
 +  auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 +* Make [`redundant_clone`] also trigger on cases where the cloned value is not
 +  consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
 +* Expand [`integer_arithmetic`] to also disallow bit-shifting [#5430](https://github.com/rust-lang/rust-clippy/pull/5430)
 +* [`option_as_ref_deref`] now detects more deref cases [#5425](https://github.com/rust-lang/rust-clippy/pull/5425)
 +* [`large_enum_variant`] now report the sizes of the largest and second-largest variants [#5466](https://github.com/rust-lang/rust-clippy/pull/5466)
 +* [`bool_comparison`] now also checks for inequality comparisons that can be
 +  written more concisely [#5365](https://github.com/rust-lang/rust-clippy/pull/5365)
 +* Expand [`clone_on_copy`] to work in method call arguments as well [#5441](https://github.com/rust-lang/rust-clippy/pull/5441)
 +* [`redundant_pattern_matching`] now also handles `while let` [#5483](https://github.com/rust-lang/rust-clippy/pull/5483)
 +* [`integer_arithmetic`] now also lints references of integers [#5329](https://github.com/rust-lang/rust-clippy/pull/5329)
 +* Expand [`float_cmp_const`] to also work on arrays [#5345](https://github.com/rust-lang/rust-clippy/pull/5345)
 +* Trigger [`map_flatten`] when map is called on an `Option` [#5473](https://github.com/rust-lang/rust-clippy/pull/5473)
 +
 +### False Positive Fixes
 +
 +* [`many_single_char_names`] [#5468](https://github.com/rust-lang/rust-clippy/pull/5468)
 +* [`should_implement_trait`] [#5437](https://github.com/rust-lang/rust-clippy/pull/5437)
 +* [`unused_self`] [#5387](https://github.com/rust-lang/rust-clippy/pull/5387)
 +* [`redundant_clone`] [#5453](https://github.com/rust-lang/rust-clippy/pull/5453)
 +* [`precedence`] [#5445](https://github.com/rust-lang/rust-clippy/pull/5445)
 +* [`suspicious_op_assign_impl`] [#5424](https://github.com/rust-lang/rust-clippy/pull/5424)
 +* [`needless_lifetimes`] [#5293](https://github.com/rust-lang/rust-clippy/pull/5293)
 +* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 +* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 +
 +
 +### Suggestion Improvements
 +
 +* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
 +* Improve the suggested placeholder in [`option_map_unit_fn`] [#5292](https://github.com/rust-lang/rust-clippy/pull/5292)
 +* Improve suggestion for [`match_single_binding`] when triggered inside a closure [#5350](https://github.com/rust-lang/rust-clippy/pull/5350)
 +
 +### ICE Fixes
 +
 +* Handle the unstable `trivial_bounds` feature [#5296](https://github.com/rust-lang/rust-clippy/pull/5296)
 +* `shadow_*` lints [#5297](https://github.com/rust-lang/rust-clippy/pull/5297)
 +
 +### Documentation
 +
 +* Fix documentation generation for configurable lints [#5353](https://github.com/rust-lang/rust-clippy/pull/5353)
 +* Update documentation for [`new_ret_no_self`] [#5448](https://github.com/rust-lang/rust-clippy/pull/5448)
 +* The documentation for [`option_option`] now suggest using a tri-state enum [#5403](https://github.com/rust-lang/rust-clippy/pull/5403)
 +* Fix bit mask example in [`verbose_bit_mask`] documentation [#5454](https://github.com/rust-lang/rust-clippy/pull/5454)
 +* [`wildcard_imports`] documentation now mentions that `use ...::prelude::*` is
 +  not linted [#5312](https://github.com/rust-lang/rust-clippy/pull/5312)
 +
 +## Rust 1.43
 +
 +Released 2020-04-23
 +
 +[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 +
 +### New lints
 +
 +* [`imprecise_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`suboptimal_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`wildcard_imports`] [#5029](https://github.com/rust-lang/rust-clippy/pull/5029)
 +* [`single_component_path_imports`] [#5058](https://github.com/rust-lang/rust-clippy/pull/5058)
 +* [`match_single_binding`] [#5061](https://github.com/rust-lang/rust-clippy/pull/5061)
 +* [`let_underscore_lock`] [#5101](https://github.com/rust-lang/rust-clippy/pull/5101)
 +* [`struct_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`fn_params_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`option_env_unwrap`] [#5148](https://github.com/rust-lang/rust-clippy/pull/5148)
 +* [`lossy_float_literal`] [#5202](https://github.com/rust-lang/rust-clippy/pull/5202)
 +* [`rest_pat_in_fully_bound_structs`] [#5258](https://github.com/rust-lang/rust-clippy/pull/5258)
 +
 +### Moves and Deprecations
 +
 +* Move [`unneeded_field_pattern`] to pedantic group [#5200](https://github.com/rust-lang/rust-clippy/pull/5200)
 +
 +### Enhancements
 +
 +* Make [`missing_errors_doc`] lint also trigger on `async` functions
 +  [#5181](https://github.com/rust-lang/rust-clippy/pull/5181)
 +* Add more constants to [`approx_constant`] [#5193](https://github.com/rust-lang/rust-clippy/pull/5193)
 +* Extend [`question_mark`] lint [#5266](https://github.com/rust-lang/rust-clippy/pull/5266)
 +
 +### False Positive Fixes
 +
 +* [`use_debug`] [#5047](https://github.com/rust-lang/rust-clippy/pull/5047)
 +* [`unnecessary_unwrap`] [#5132](https://github.com/rust-lang/rust-clippy/pull/5132)
 +* [`zero_prefixed_literal`] [#5170](https://github.com/rust-lang/rust-clippy/pull/5170)
 +* [`missing_const_for_fn`] [#5216](https://github.com/rust-lang/rust-clippy/pull/5216)
 +
 +### Suggestion Improvements
 +
 +* Improve suggestion when blocks of code are suggested [#5134](https://github.com/rust-lang/rust-clippy/pull/5134)
 +
 +### ICE Fixes
 +
 +* `misc_early` lints [#5129](https://github.com/rust-lang/rust-clippy/pull/5129)
 +* [`missing_errors_doc`] [#5213](https://github.com/rust-lang/rust-clippy/pull/5213)
 +* Fix ICE when evaluating `usize`s [#5256](https://github.com/rust-lang/rust-clippy/pull/5256)
 +
 +### Documentation
 +
 +* Improve documentation of [`iter_nth_zero`]
 +* Add documentation pages for stable releases [#5171](https://github.com/rust-lang/rust-clippy/pull/5171)
 +
 +### Others
 +
 +* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 +
 +
 +## Rust 1.42
 +
 +Released 2020-03-12
 +
 +[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206)
 +
 +### New lints
 +
 +* [`filetype_is_file`] [#4543](https://github.com/rust-lang/rust-clippy/pull/4543)
 +* [`let_underscore_must_use`] [#4823](https://github.com/rust-lang/rust-clippy/pull/4823)
 +* [`modulo_arithmetic`] [#4867](https://github.com/rust-lang/rust-clippy/pull/4867)
 +* [`mem_replace_with_default`] [#4881](https://github.com/rust-lang/rust-clippy/pull/4881)
 +* [`mutable_key_type`] [#4885](https://github.com/rust-lang/rust-clippy/pull/4885)
 +* [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945)
 +* [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960)
 +* [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966)
 +* [`invalid_atomic_ordering`] [#4999](https://github.com/rust-lang/rust-clippy/pull/4999)
 +* [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067)
 +
 +### Moves and Deprecations
 +
 +* Move [`transmute_float_to_int`] from nursery to complexity group
 +  [#5015](https://github.com/rust-lang/rust-clippy/pull/5015)
 +* Move [`range_plus_one`] to pedantic group [#5057](https://github.com/rust-lang/rust-clippy/pull/5057)
 +* Move [`debug_assert_with_mut_call`] to nursery group [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Deprecate [`unused_label`] [#4930](https://github.com/rust-lang/rust-clippy/pull/4930)
 +
 +### Enhancements
 +
 +* Lint vectored IO in [`unused_io_amount`] [#5027](https://github.com/rust-lang/rust-clippy/pull/5027)
 +* Make [`vec_box`] configurable by adding a size threshold [#5081](https://github.com/rust-lang/rust-clippy/pull/5081)
 +* Also lint constants in [`cmp_nan`] [#4910](https://github.com/rust-lang/rust-clippy/pull/4910)
 +* Fix false negative in [`expect_fun_call`] [#4915](https://github.com/rust-lang/rust-clippy/pull/4915)
 +* Fix false negative in [`redundant_clone`] [#5017](https://github.com/rust-lang/rust-clippy/pull/5017)
 +
 +### False Positive Fixes
 +
 +* [`map_clone`] [#4937](https://github.com/rust-lang/rust-clippy/pull/4937)
 +* [`replace_consts`] [#4977](https://github.com/rust-lang/rust-clippy/pull/4977)
 +* [`let_and_return`] [#5008](https://github.com/rust-lang/rust-clippy/pull/5008)
 +* [`eq_op`] [#5079](https://github.com/rust-lang/rust-clippy/pull/5079)
 +* [`possible_missing_comma`] [#5083](https://github.com/rust-lang/rust-clippy/pull/5083)
 +* [`debug_assert_with_mut_call`] [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Don't trigger [`let_underscore_must_use`] in external macros
 +  [#5082](https://github.com/rust-lang/rust-clippy/pull/5082)
 +* Don't trigger [`empty_loop`] in `no_std` crates [#5086](https://github.com/rust-lang/rust-clippy/pull/5086)
 +
 +### Suggestion Improvements
 +
 +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634)
 +* [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934)
 +* [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935)
 +* [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956)
 +* [`unknown_clippy_lints`] [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
 +* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
 +* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
 +* [`if_let_some_result`] [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
 +
 +### ICE fixes
 +
 +* [`unsound_collection_transmute`] [#4975](https://github.com/rust-lang/rust-clippy/pull/4975)
 +
 +### Documentation
 +
 +* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 +
 +
 +## Rust 1.41
 +
 +Released 2020-01-30
 +
 +[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7)
 +
 +* New Lints:
 +  * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
 +  * [`to_digit_is_some`] [#4801](https://github.com/rust-lang/rust-clippy/pull/4801)
 +  * [`tabs_in_doc_comments`] [#4806](https://github.com/rust-lang/rust-clippy/pull/4806)
 +  * [`large_stack_arrays`] [#4807](https://github.com/rust-lang/rust-clippy/pull/4807)
 +  * [`same_functions_in_if_condition`] [#4814](https://github.com/rust-lang/rust-clippy/pull/4814)
 +  * [`zst_offset`] [#4816](https://github.com/rust-lang/rust-clippy/pull/4816)
 +  * [`as_conversions`] [#4821](https://github.com/rust-lang/rust-clippy/pull/4821)
 +  * [`missing_errors_doc`] [#4884](https://github.com/rust-lang/rust-clippy/pull/4884)
 +  * [`transmute_float_to_int`] [#4889](https://github.com/rust-lang/rust-clippy/pull/4889)
 +* Remove plugin interface, see
 +  [Inside Rust Blog](https://blog.rust-lang.org/inside-rust/2019/11/04/Clippy-removes-plugin-interface.html) for
 +  details [#4714](https://github.com/rust-lang/rust-clippy/pull/4714)
 +* Move [`use_self`] to nursery group [#4863](https://github.com/rust-lang/rust-clippy/pull/4863)
 +* Deprecate [`into_iter_on_array`] [#4788](https://github.com/rust-lang/rust-clippy/pull/4788)
 +* Expand [`string_lit_as_bytes`] to also trigger when literal has escapes
 +  [#4808](https://github.com/rust-lang/rust-clippy/pull/4808)
 +* Fix false positive in `comparison_chain` [#4842](https://github.com/rust-lang/rust-clippy/pull/4842)
 +* Fix false positive in `while_immutable_condition` [#4730](https://github.com/rust-lang/rust-clippy/pull/4730)
 +* Fix false positive in `explicit_counter_loop` [#4803](https://github.com/rust-lang/rust-clippy/pull/4803)
 +* Fix false positive in `must_use_candidate` [#4794](https://github.com/rust-lang/rust-clippy/pull/4794)
 +* Fix false positive in `print_with_newline` and `write_with_newline`
 +  [#4769](https://github.com/rust-lang/rust-clippy/pull/4769)
 +* Fix false positive in `derive_hash_xor_eq` [#4766](https://github.com/rust-lang/rust-clippy/pull/4766)
 +* Fix false positive in `missing_inline_in_public_items` [#4870](https://github.com/rust-lang/rust-clippy/pull/4870)
 +* Fix false positive in `string_add` [#4880](https://github.com/rust-lang/rust-clippy/pull/4880)
 +* Fix false positive in `float_arithmetic` [#4851](https://github.com/rust-lang/rust-clippy/pull/4851)
 +* Fix false positive in `cast_sign_loss` [#4883](https://github.com/rust-lang/rust-clippy/pull/4883)
 +* Fix false positive in `manual_swap` [#4877](https://github.com/rust-lang/rust-clippy/pull/4877)
 +* Fix ICEs occurring while checking some block expressions [#4772](https://github.com/rust-lang/rust-clippy/pull/4772)
 +* Fix ICE in `use_self` [#4776](https://github.com/rust-lang/rust-clippy/pull/4776)
 +* Fix ICEs related to `const_generics` [#4780](https://github.com/rust-lang/rust-clippy/pull/4780)
 +* Display help when running `clippy-driver` without arguments, instead of ICEing
 +  [#4810](https://github.com/rust-lang/rust-clippy/pull/4810)
 +* Clippy has its own ICE message now [#4588](https://github.com/rust-lang/rust-clippy/pull/4588)
 +* Show deprecated lints in the documentation again [#4757](https://github.com/rust-lang/rust-clippy/pull/4757)
 +* Improve Documentation by adding positive examples to some lints
 +  [#4832](https://github.com/rust-lang/rust-clippy/pull/4832)
 +
 +## Rust 1.40
 +
 +Released 2019-12-19
 +
 +[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb)
 +
 +* New Lints:
 +  * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
 +  * [`needless_doctest_main`] [#4603](https://github.com/rust-lang/rust-clippy/pull/4603)
 +  * [`suspicious_unary_op_formatting`] [#4615](https://github.com/rust-lang/rust-clippy/pull/4615)
 +  * [`debug_assert_with_mut_call`] [#4680](https://github.com/rust-lang/rust-clippy/pull/4680)
 +  * [`unused_self`] [#4619](https://github.com/rust-lang/rust-clippy/pull/4619)
 +  * [`inefficient_to_string`] [#4683](https://github.com/rust-lang/rust-clippy/pull/4683)
 +  * [`must_use_unit`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`must_use_candidate`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`double_must_use`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`comparison_chain`] [#4569](https://github.com/rust-lang/rust-clippy/pull/4569)
 +  * [`unsound_collection_transmute`] [#4592](https://github.com/rust-lang/rust-clippy/pull/4592)
 +  * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +* Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736)
 +* Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613)
 +* Expand `integer_arithmetic` to also detect mutating arithmetic like `+=` [#4585](https://github.com/rust-lang/rust-clippy/pull/4585)
 +* Fix false positive in `nonminimal_bool` [#4568](https://github.com/rust-lang/rust-clippy/pull/4568)
 +* Fix false positive in `missing_safety_doc` [#4611](https://github.com/rust-lang/rust-clippy/pull/4611)
 +* Fix false positive in `cast_sign_loss` [#4614](https://github.com/rust-lang/rust-clippy/pull/4614)
 +* Fix false positive in `redundant_clone` [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Fix false positive in `try_err` [#4721](https://github.com/rust-lang/rust-clippy/pull/4721)
 +* Fix false positive in `toplevel_ref_arg` [#4570](https://github.com/rust-lang/rust-clippy/pull/4570)
 +* Fix false positive in `multiple_inherent_impl` [#4593](https://github.com/rust-lang/rust-clippy/pull/4593)
 +* Improve more suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4575](https://github.com/rust-lang/rust-clippy/pull/4575)
 +* Improve suggestion for `zero_ptr` [#4599](https://github.com/rust-lang/rust-clippy/pull/4599)
 +* Improve suggestion for `explicit_counter_loop` [#4691](https://github.com/rust-lang/rust-clippy/pull/4691)
 +* Improve suggestion for `mul_add` [#4602](https://github.com/rust-lang/rust-clippy/pull/4602)
 +* Improve suggestion for `assertions_on_constants` [#4635](https://github.com/rust-lang/rust-clippy/pull/4635)
 +* Fix ICE in `use_self` [#4671](https://github.com/rust-lang/rust-clippy/pull/4671)
 +* Fix ICE when encountering const casts [#4590](https://github.com/rust-lang/rust-clippy/pull/4590)
 +
 +## Rust 1.39
 +
 +Released 2019-11-07
 +
 +[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b)
 +
 +* New Lints:
 +  * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
 +  * [`flat_map_identity`] [#4231](https://github.com/rust-lang/rust-clippy/pull/4231)
 +  * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535)
 +  * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511)
 +  * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394)
 +  * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386)
 +  * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498)
 +* Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348)
 +* Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403)
 +* Move `cast_lossless` to pedantic group [#4539](https://github.com/rust-lang/rust-clippy/pull/4539)
 +* `temporary_cstring_as_ptr` now catches more cases [#4425](https://github.com/rust-lang/rust-clippy/pull/4425)
 +* `use_self` now works in constructors, too [#4525](https://github.com/rust-lang/rust-clippy/pull/4525)
 +* `cargo_common_metadata` now checks for license files [#4518](https://github.com/rust-lang/rust-clippy/pull/4518)
 +* `cognitive_complexity` now includes the measured complexity in the warning message [#4469](https://github.com/rust-lang/rust-clippy/pull/4469)
 +* Fix false positives in `block_in_if_*` lints [#4458](https://github.com/rust-lang/rust-clippy/pull/4458)
 +* Fix false positive in `cast_lossless` [#4473](https://github.com/rust-lang/rust-clippy/pull/4473)
 +* Fix false positive in `clone_on_copy` [#4411](https://github.com/rust-lang/rust-clippy/pull/4411)
 +* Fix false positive in `deref_addrof` [#4487](https://github.com/rust-lang/rust-clippy/pull/4487)
 +* Fix false positive in `too_many_lines` [#4490](https://github.com/rust-lang/rust-clippy/pull/4490)
 +* Fix false positive in `new_ret_no_self` [#4365](https://github.com/rust-lang/rust-clippy/pull/4365)
 +* Fix false positive in `manual_swap` [#4478](https://github.com/rust-lang/rust-clippy/pull/4478)
 +* Fix false positive in `missing_const_for_fn` [#4450](https://github.com/rust-lang/rust-clippy/pull/4450)
 +* Fix false positive in `extra_unused_lifetimes` [#4477](https://github.com/rust-lang/rust-clippy/pull/4477)
 +* Fix false positive in `inherent_to_string` [#4460](https://github.com/rust-lang/rust-clippy/pull/4460)
 +* Fix false positive in `map_entry` [#4495](https://github.com/rust-lang/rust-clippy/pull/4495)
 +* Fix false positive in `unused_unit` [#4445](https://github.com/rust-lang/rust-clippy/pull/4445)
 +* Fix false positive in `redundant_pattern` [#4489](https://github.com/rust-lang/rust-clippy/pull/4489)
 +* Fix false positive in `wrong_self_convention` [#4369](https://github.com/rust-lang/rust-clippy/pull/4369)
 +* Improve various suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4558](https://github.com/rust-lang/rust-clippy/pull/4558)
 +* Improve suggestions for `redundant_pattern_matching` [#4352](https://github.com/rust-lang/rust-clippy/pull/4352)
 +* Improve suggestions for `explicit_write` [#4544](https://github.com/rust-lang/rust-clippy/pull/4544)
 +* Improve suggestion for `or_fun_call` [#4522](https://github.com/rust-lang/rust-clippy/pull/4522)
 +* Improve suggestion for `match_as_ref` [#4446](https://github.com/rust-lang/rust-clippy/pull/4446)
 +* Improve suggestion for `unnecessary_fold_span` [#4382](https://github.com/rust-lang/rust-clippy/pull/4382)
 +* Add suggestions for `unseparated_literal_suffix` [#4401](https://github.com/rust-lang/rust-clippy/pull/4401)
 +* Add suggestions for `char_lit_as_u8` [#4418](https://github.com/rust-lang/rust-clippy/pull/4418)
 +
 +## Rust 1.38
 +
 +Released 2019-09-26
 +
 +[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860)
 +
 +* New Lints:
 +  * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
 +  * [`inherent_to_string`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`inherent_to_string_shadow_display`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`type_repetition_in_bounds`] [#3766](https://github.com/rust-lang/rust-clippy/pull/3766)
 +  * [`try_err`] [#4222](https://github.com/rust-lang/rust-clippy/pull/4222)
 +* Move `{unnnecessary,panicking}_unwrap` out of nursery [#4307](https://github.com/rust-lang/rust-clippy/pull/4307)
 +* Extend the `use_self` lint to suggest uses of `Self::Variant` [#4308](https://github.com/rust-lang/rust-clippy/pull/4308)
 +* Improve suggestion for needless return [#4262](https://github.com/rust-lang/rust-clippy/pull/4262)
 +* Add auto-fixable suggestion for `let_unit` [#4337](https://github.com/rust-lang/rust-clippy/pull/4337)
 +* Fix false positive in `pub_enum_variant_names` and `enum_variant_names` [#4345](https://github.com/rust-lang/rust-clippy/pull/4345)
 +* Fix false positive in `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Fix false positive in `string_lit_as_bytes` [#4233](https://github.com/rust-lang/rust-clippy/pull/4233)
 +* Fix false positive in `needless_lifetimes` [#4266](https://github.com/rust-lang/rust-clippy/pull/4266)
 +* Fix false positive in `float_cmp` [#4275](https://github.com/rust-lang/rust-clippy/pull/4275)
 +* Fix false positives in `needless_return` [#4274](https://github.com/rust-lang/rust-clippy/pull/4274)
 +* Fix false negative in `match_same_arms` [#4246](https://github.com/rust-lang/rust-clippy/pull/4246)
 +* Fix incorrect suggestion for `needless_bool` [#4335](https://github.com/rust-lang/rust-clippy/pull/4335)
 +* Improve suggestion for `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Improve suggestion for `single_char_literal` [#4361](https://github.com/rust-lang/rust-clippy/pull/4361)
 +* Improve suggestion for `len_zero` [#4314](https://github.com/rust-lang/rust-clippy/pull/4314)
 +* Fix ICE in `implicit_hasher` [#4268](https://github.com/rust-lang/rust-clippy/pull/4268)
 +* Fix allow bug in `trivially_copy_pass_by_ref` [#4250](https://github.com/rust-lang/rust-clippy/pull/4250)
 +
 +## Rust 1.37
 +
 +Released 2019-08-15
 +
 +[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e)
 +
 +* New Lints:
 +  * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
 +  * [`get_last_with_len`] [#3832](https://github.com/rust-lang/rust-clippy/pull/3832)
 +  * [`integer_division`] [#4195](https://github.com/rust-lang/rust-clippy/pull/4195)
 +* Renamed Lint: `const_static_lifetime` is now called [`redundant_static_lifetimes`].
 +  The lint now covers statics in addition to consts [#4162](https://github.com/rust-lang/rust-clippy/pull/4162)
 +* [`match_same_arms`] now warns for all identical arms, instead of only the first one [#4102](https://github.com/rust-lang/rust-clippy/pull/4102)
 +* [`needless_return`] now works with void functions [#4220](https://github.com/rust-lang/rust-clippy/pull/4220)
 +* Fix false positive in [`redundant_closure`] [#4190](https://github.com/rust-lang/rust-clippy/pull/4190)
 +* Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107)
 +* Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214)
 +* Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136)
 +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164)
 +* Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119)
 +* Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137)
 +* Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071)
 +* Add macro check for [`unreadable_literal`] [#4099](https://github.com/rust-lang/rust-clippy/pull/4099)
 +
 +## Rust 1.36
 +
 +Released 2019-07-04
 +
 +[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7)
 +
 +* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
 +* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
 +* Move `path_buf_push_overwrite` to the nursery [#4013](https://github.com/rust-lang/rust-clippy/pull/4013)
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Allow allowing of [`toplevel_ref_arg`] lint [#4007](https://github.com/rust-lang/rust-clippy/pull/4007)
 +* Fix false negative in [`or_fun_call`] pertaining to nested constructors [#4084](https://github.com/rust-lang/rust-clippy/pull/4084)
 +* Fix false positive in [`or_fun_call`] pertaining to enum variant constructors [#4018](https://github.com/rust-lang/rust-clippy/pull/4018)
 +* Fix false positive in [`useless_let_if_seq`] pertaining to interior mutability [#4035](https://github.com/rust-lang/rust-clippy/pull/4035)
 +* Fix false positive in [`redundant_closure`] pertaining to non-function types [#4008](https://github.com/rust-lang/rust-clippy/pull/4008)
 +* Fix false positive in [`let_and_return`] pertaining to attributes on `let`s [#4024](https://github.com/rust-lang/rust-clippy/pull/4024)
 +* Fix false positive in [`module_name_repetitions`] lint pertaining to attributes [#4006](https://github.com/rust-lang/rust-clippy/pull/4006)
 +* Fix false positive on [`assertions_on_constants`] pertaining to `debug_assert!` [#3989](https://github.com/rust-lang/rust-clippy/pull/3989)
 +* Improve suggestion in [`map_clone`] to suggest `.copied()` where applicable  [#3970](https://github.com/rust-lang/rust-clippy/pull/3970) [#4043](https://github.com/rust-lang/rust-clippy/pull/4043)
 +* Improve suggestion for [`search_is_some`] [#4049](https://github.com/rust-lang/rust-clippy/pull/4049)
 +* Improve suggestion applicability for [`naive_bytecount`] [#3984](https://github.com/rust-lang/rust-clippy/pull/3984)
 +* Improve suggestion applicability for [`while_let_loop`] [#3975](https://github.com/rust-lang/rust-clippy/pull/3975)
 +* Improve diagnostics for [`too_many_arguments`] [#4053](https://github.com/rust-lang/rust-clippy/pull/4053)
 +* Improve diagnostics for [`cast_lossless`] [#4021](https://github.com/rust-lang/rust-clippy/pull/4021)
 +* Deal with macro checks in desugarings better [#4082](https://github.com/rust-lang/rust-clippy/pull/4082)
 +* Add macro check for [`unnecessary_cast`]  [#4026](https://github.com/rust-lang/rust-clippy/pull/4026)
 +* Remove [`approx_constant`]'s documentation's "Known problems" section. [#4027](https://github.com/rust-lang/rust-clippy/pull/4027)
 +* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 +* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 +
 +
 +## Rust 1.35
 +
 +Released 2019-05-20
 +
 +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
 +
 +* New lint: [`drop_bounds`] to detect `T: Drop` bounds
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
 +* Move [`get_unwrap`] to the restriction category
 +* Improve suggestions for [`iter_cloned_collect`]
 +* Improve suggestions for [`cast_lossless`] to suggest suffixed literals
 +* Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
 +* Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
 +* Fix false positive in [`bool_comparison`] pertaining to non-bool types
 +* Fix false positive in [`redundant_closure`] pertaining to differences in borrows
 +* Fix false positive in `option_map_unwrap_or` on non-copy types
 +* Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
 +* Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
 +* Fix false positive in [`needless_continue`] pertaining to loop labels
 +* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 +* Fix false positive for [`use_self`] in nested functions
 +* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
 +* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 +* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 +* Avoid triggering [`redundant_closure`] in macros
 +* ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
 +
 +## Rust 1.34
 +
 +Released 2019-04-10
 +
 +[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
 +
 +* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
 +* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
 +* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
 +* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
 +  configured using the `too-many-lines-threshold` configuration.
 +* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
 +* Expand `redundant_closure` to also work for methods (not only functions)
 +* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
 +* Fix false positive in `cast_sign_loss`
 +* Fix false positive in `integer_arithmetic`
 +* Fix false positive in `unit_arg`
 +* Fix false positives in `implicit_return`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `cast_lossless`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `needless_bool`
 +* Fix incorrect suggestion for `needless_range_loop`
 +* Fix incorrect suggestion for `use_self`
 +* Fix incorrect suggestion for `while_let_on_iterator`
 +* Clippy is now slightly easier to invoke in non-cargo contexts. See
 +  [#3665][pull3665] for more details.
 +* We now have [improved documentation][adding_lints] on how to add new lints
 +
 +## Rust 1.33
 +
 +Released 2019-02-26
 +
 +[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
 +
 +* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
 +* The `rust-clippy` repository is now part of the `rust-lang` org.
 +* Rename `stutter` to `module_name_repetitions`
 +* Merge `new_without_default_derive` into `new_without_default` lint
 +* Move `large_digit_groups` from `style` group to `pedantic`
 +* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
 +  comparisons against booleans
 +* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
 +* Expand `redundant_clone` to work on struct fields
 +* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
 +* Expand `use_self` to work on tuple structs and also in local macros
 +* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
 +* Fix false positives in `implicit_return`
 +* Fix false positives in `use_self`
 +* Fix false negative in `clone_on_copy`
 +* Fix false positive in `doc_markdown`
 +* Fix false positive in `empty_loop`
 +* Fix false positive in `if_same_then_else`
 +* Fix false positive in `infinite_iter`
 +* Fix false positive in `question_mark`
 +* Fix false positive in `useless_asref`
 +* Fix false positive in `wildcard_dependencies`
 +* Fix false positive in `write_with_newline`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `get_unwrap`
 +
 +## Rust 1.32
 +
 +Released 2019-01-17
 +
 +[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 +
 +* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`],
 +  [`redundant_clone`], [`wildcard_dependencies`],
 +  [`into_iter_on_ref`], [`into_iter_on_array`], [`deprecated_cfg_attr`],
 +  [`mem_discriminant_non_enum`], [`cargo_common_metadata`]
 +* Add support for `u128` and `i128` to integer related lints
 +* Add float support to `mistyped_literal_suffixes`
 +* Fix false positives in `use_self`
 +* Fix false positives in `missing_comma`
 +* Fix false positives in `new_ret_no_self`
 +* Fix false positives in `possible_missing_comma`
 +* Fix false positive in `integer_arithmetic` in constant items
 +* Fix false positive in `needless_borrow`
 +* Fix false positive in `out_of_bounds_indexing`
 +* Fix false positive in `new_without_default_derive`
 +* Fix false positive in `string_lit_as_bytes`
 +* Fix false negative in `out_of_bounds_indexing`
 +* Fix false negative in `use_self`. It will now also check existential types
 +* Fix incorrect suggestion for `redundant_closure_call`
 +* Fix various suggestions that contained expanded macros
 +* Fix `bool_comparison` triggering 3 times on on on the same code
 +* Expand `trivially_copy_pass_by_ref` to work on trait methods
 +* Improve suggestion for `needless_range_loop`
 +* Move `needless_pass_by_value` from `pedantic` group to `style`
 +
 +## Rust 1.31
 +
 +Released 2018-12-06
 +
 +[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
 +
 +* Clippy has been relicensed under a dual MIT / Apache license.
 +  See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
 +  information.
 +* With Rust 1.31, Clippy is no longer available via crates.io. The recommended
 +  installation method is via `rustup component add clippy`.
 +* New lints: [`redundant_pattern_matching`], [`unnecessary_filter_map`],
 +  [`unused_unit`], [`map_flatten`], [`mem_replace_option_with_none`]
 +* Fix ICE in `if_let_redundant_pattern_matching`
 +* Fix ICE in `needless_pass_by_value` when encountering a generic function
 +  argument with a lifetime parameter
 +* Fix ICE in `needless_range_loop`
 +* Fix ICE in `single_char_pattern` when encountering a constant value
 +* Fix false positive in `assign_op_pattern`
 +* Fix false positive in `boxed_local` on trait implementations
 +* Fix false positive in `cmp_owned`
 +* Fix false positive in `collapsible_if` when conditionals have comments
 +* Fix false positive in `double_parens`
 +* Fix false positive in `excessive_precision`
 +* Fix false positive in `explicit_counter_loop`
 +* Fix false positive in `fn_to_numeric_cast_with_truncation`
 +* Fix false positive in `map_clone`
 +* Fix false positive in `new_ret_no_self`
 +* Fix false positive in `new_without_default` when `new` is unsafe
 +* Fix false positive in `type_complexity` when using extern types
 +* Fix false positive in `useless_format`
 +* Fix false positive in `wrong_self_convention`
 +* Fix incorrect suggestion for `excessive_precision`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `get_unwrap`
 +* Fix incorrect suggestion for `useless_format`
 +* `fn_to_numeric_cast_with_truncation` lint can be disabled again
 +* Improve suggestions for `manual_memcpy`
 +* Improve help message for `needless_lifetimes`
 +
 +## Rust 1.30
 +
 +Released 2018-10-25
 +
 +[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad)
 +
 +* Deprecate `assign_ops` lint
 +* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
 +  [`needless_collect`], [`copy_iterator`]
 +* `cargo clippy -V` now includes the Clippy commit hash of the Rust
 +  Clippy component
 +* Fix ICE in `implicit_hasher`
 +* Fix ICE when encountering `println!("{}" a);`
 +* Fix ICE when encountering a macro call in match statements
 +* Fix false positive in `default_trait_access`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `similar_names`
 +* Fix false positive in `redundant_field_name`
 +* Fix false positive in `expect_fun_call`
 +* Fix false negative in `identity_conversion`
 +* Fix false negative in `explicit_counter_loop`
 +* Fix `range_plus_one` suggestion and false negative
 +* `print_with_newline` / `write_with_newline`: don't warn about string with several `\n`s in them
 +* Fix `useless_attribute` to also whitelist `unused_extern_crates`
 +* Fix incorrect suggestion for `single_char_pattern`
 +* Improve suggestion for `identity_conversion` lint
 +* Move `explicit_iter_loop` and `explicit_into_iter_loop` from `style` group to `pedantic`
 +* Move `range_plus_one` and `range_minus_one` from `nursery` group to `complexity`
 +* Move `shadow_unrelated` from `restriction` group to `pedantic`
 +* Move `indexing_slicing` from `pedantic` group to `restriction`
 +
 +## Rust 1.29
 +
 +Released 2018-09-13
 +
 +[v0.0.212...14207503](https://github.com/rust-lang/rust-clippy/compare/v0.0.212...14207503)
 +
 +* :tada: :tada: **Rust 1.29 is the first stable Rust that includes a bundled Clippy** :tada:
 +  :tada:
 +  You can now run `rustup component add clippy-preview` and then `cargo
 +  clippy` to run Clippy. This should put an end to the continuous nightly
 +  upgrades for Clippy users.
 +* Clippy now follows the Rust versioning scheme instead of its own
 +* Fix ICE when encountering a `while let (..) = x.iter()` construct
 +* Fix false positives in `use_self`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `useless_attribute` lint
 +* Fix false positive in `print_literal`
 +* Fix `use_self` regressions
 +* Improve lint message for `neg_cmp_op_on_partial_ord`
 +* Improve suggestion highlight for `single_char_pattern`
 +* Improve suggestions for various print/write macro lints
 +* Improve website header
 +
 +## 0.0.212 (2018-07-10)
 +* Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 +
 +## 0.0.211
 +* Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
 +
 +## 0.0.210
 +* Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
 +
 +## 0.0.209
 +* Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
 +
 +## 0.0.208
 +* Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
 +
 +## 0.0.207
 +* Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
 +
 +## 0.0.206
 +* Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
 +
 +## 0.0.205
 +* Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
 +* Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
 +
 +## 0.0.204
 +* Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
 +
 +## 0.0.203
 +* Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
 +* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 +
 +## 0.0.202
 +* Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
 +
 +## 0.0.201
 +* Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
 +
 +## 0.0.200
 +* Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
 +
 +## 0.0.199
 +* Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
 +
 +## 0.0.198
 +* Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
 +
 +## 0.0.197
 +* Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
 +
 +## 0.0.196
 +* Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
 +
 +## 0.0.195
 +* Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
 +
 +## 0.0.194
 +* Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
 +* New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
 +
 +## 0.0.193
 +* Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
 +
 +## 0.0.192
 +* Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
 +* New lint: [`print_literal`]
 +
 +## 0.0.191
 +* Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
 +* Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
 +
 +## 0.0.190
 +* Fix a bunch of intermittent cargo bugs
 +
 +## 0.0.189
 +* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
 +
 +## 0.0.188
 +* Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
 +* New lint: [`while_immutable_condition`]
 +
 +## 0.0.187
 +* Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
 +* New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
 +
 +## 0.0.186
 +* Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
 +* Various false positive fixes
 +
 +## 0.0.185
 +* Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
 +* New lint: [`question_mark`]
 +
 +## 0.0.184
 +* Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
 +* New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
 +
 +## 0.0.183
 +* Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
 +* New lint: [`misaligned_transmute`]
 +
 +## 0.0.182
 +* Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
 +* New lint: [`decimal_literal_representation`]
 +
 +## 0.0.181
 +* Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
 +* New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
 +* Removed `unit_expr`
 +* Various false positive fixes for [`needless_pass_by_value`]
 +
 +## 0.0.180
 +* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
 +
 +## 0.0.179
 +* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
 +
 +## 0.0.178
 +* Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
 +
 +## 0.0.177
 +* Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
 +* New lint: [`match_as_ref`]
 +
 +## 0.0.176
 +* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
 +
 +## 0.0.175
 +* Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
 +
 +## 0.0.174
 +* Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
 +
 +## 0.0.173
 +* Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
 +
 +## 0.0.172
 +* Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
 +
 +## 0.0.171
 +* Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
 +
 +## 0.0.170
 +* Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
 +
 +## 0.0.169
 +* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
 +* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
 +
 +## 0.0.168
 +* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
 +
 +## 0.0.167
 +* Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
 +* New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
 +
 +## 0.0.166
 +* Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
 +* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], [`invalid_ref`], [`option_map_or_none`],
 +  [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
 +  [`transmute_int_to_float`]
 +
 +## 0.0.165
 +* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
 +* New lint: [`mut_range_bound`]
 +
 +## 0.0.164
 +* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
 +* New lint: [`int_plus_one`]
 +
 +## 0.0.163
 +* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
 +
 +## 0.0.162
 +* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
 +* New lint: [`chars_last_cmp`]
 +* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
 +
 +## 0.0.161
 +* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
 +
 +## 0.0.160
 +* Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
 +
 +## 0.0.159
 +* Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
 +* New lint: [`clone_on_ref_ptr`]
 +
 +## 0.0.158
 +* New lint: [`manual_memcpy`]
 +* [`cast_lossless`] no longer has redundant parentheses in its suggestions
 +* Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
 +
 +## 0.0.157 - 2017-09-04
 +* Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
 +* New lint: `unit_expr`
 +
 +## 0.0.156 - 2017-09-03
 +* Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
 +
 +## 0.0.155
 +* Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
 +* New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
 +
 +## 0.0.154
 +* Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
 +* Fix [`use_self`] triggering inside derives
 +* Add support for linting an entire workspace with `cargo clippy --all`
 +* New lint: [`naive_bytecount`]
 +
 +## 0.0.153
 +* Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
 +* New lint: [`use_self`]
 +
 +## 0.0.152
 +* Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
 +
 +## 0.0.151
 +* Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
 +
 +## 0.0.150
 +* Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
 +
 +## 0.0.148
 +* Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
 +* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
 +
 +## 0.0.147
 +* Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
 +
 +## 0.0.146
 +* Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
 +* Fixes false positives in `inline_always`
 +* Fixes false negatives in `panic_params`
 +
 +## 0.0.145
 +* Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
 +
 +## 0.0.144
 +* Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
 +
 +## 0.0.143
 +* Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
 +* Fix `cargo clippy` crashing on `dylib` projects
 +* Fix false positives around `nested_while_let` and `never_loop`
 +
 +## 0.0.142
 +* Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
 +
 +## 0.0.141
 +* Rewrite of the `doc_markdown` lint.
 +* Deprecated [`range_step_by_zero`]
 +* New lint: [`iterator_step_by_zero`]
 +* New lint: [`needless_borrowed_reference`]
 +* Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
 +
 +## 0.0.140 - 2017-06-16
 +* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
 +
 +## 0.0.139 — 2017-06-10
 +* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
 +* Fix bugs with for loop desugaring
 +* Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
 +
 +## 0.0.138 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
 +
 +## 0.0.137 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
 +
 +## 0.0.136 — 2017—05—26
 +* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
 +
 +## 0.0.135 — 2017—05—24
 +* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
 +
 +## 0.0.134 — 2017—05—19
 +* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
 +
 +## 0.0.133 — 2017—05—14
 +* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
 +
 +## 0.0.132 — 2017—05—05
 +* Fix various bugs and some ices
 +
 +## 0.0.131 — 2017—05—04
 +* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
 +
 +## 0.0.130 — 2017—05—03
 +* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
 +
 +## 0.0.129 — 2017-05-01
 +* Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
 +
 +## 0.0.128 — 2017-04-28
 +* Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
 +
 +## 0.0.127 — 2017-04-27
 +* Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
 +* New lint: [`needless_continue`]
 +
 +## 0.0.126 — 2017-04-24
 +* Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
 +
 +## 0.0.125 — 2017-04-19
 +* Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
 +
 +## 0.0.124 — 2017-04-16
 +* Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
 +
 +## 0.0.123 — 2017-04-07
 +* Fix various false positives
 +
 +## 0.0.122 — 2017-04-07
 +* Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
 +* New lint: [`op_ref`]
 +
 +## 0.0.121 — 2017-03-21
 +* Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
 +
 +## 0.0.120 — 2017-03-17
 +* Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
 +
 +## 0.0.119 — 2017-03-13
 +* Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
 +
 +## 0.0.118 — 2017-03-05
 +* Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
 +
 +## 0.0.117 — 2017-03-01
 +* Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
 +
 +## 0.0.116 — 2017-02-28
 +* Fix `cargo clippy` on 64 bit windows systems
 +
 +## 0.0.115 — 2017-02-27
 +* Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
 +* New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
 +
 +## 0.0.114 — 2017-02-08
 +* Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
 +* Tests are now ui tests (testing the exact output of rustc)
 +
 +## 0.0.113 — 2017-02-04
 +* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
 +* New lint: [`large_enum_variant`]
 +* `explicit_into_iter_loop` provides suggestions
 +
 +## 0.0.112 — 2017-01-27
 +* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
 +
 +## 0.0.111 — 2017-01-21
 +* Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
 +
 +## 0.0.110 — 2017-01-20
 +* Add badges and categories to `Cargo.toml`
 +
 +## 0.0.109 — 2017-01-19
 +* Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
 +
 +## 0.0.108 — 2017-01-12
 +* Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
 +
 +## 0.0.107 — 2017-01-11
 +* Update regex dependency
 +* Fix FP when matching `&&mut` by `&ref`
 +* Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
 +* New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
 +
 +## 0.0.106 — 2017-01-04
 +* Fix FP introduced by rustup in [`wrong_self_convention`]
 +
 +## 0.0.105 — 2017-01-04
 +* Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
 +* New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
 +* Fix suggestion in [`new_without_default`]
 +* FP fix in [`absurd_extreme_comparisons`]
 +
 +## 0.0.104 — 2016-12-15
 +* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
 +
 +## 0.0.103 — 2016-11-25
 +* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
 +
 +## 0.0.102 — 2016-11-24
 +* Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
 +
 +## 0.0.101 — 2016-11-23
 +* Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
 +* New lint: [`string_extend_chars`]
 +
 +## 0.0.100 — 2016-11-20
 +* Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
 +
 +## 0.0.99 — 2016-11-18
 +* Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
 +* New lint: [`get_unwrap`]
 +
 +## 0.0.98 — 2016-11-08
 +* Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
 +
 +## 0.0.97 — 2016-11-03
 +* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
 +  previously added for a short time under the name `clippy` but removed for
 +  compatibility.
 +* `cargo clippy --help` is more helping (and less helpful :smile:)
 +* Rustup to *rustc 1.14.0-nightly (5665bdf3e 2016-11-02)*
 +* New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
 +
 +## 0.0.96 — 2016-10-22
 +* Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
 +* New lint: [`iter_skip_next`]
 +
 +## 0.0.95 — 2016-10-06
 +* Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
 +
 +## 0.0.94 — 2016-10-04
 +* Fixes bustage on Windows due to forbidden directory name
 +
 +## 0.0.93 — 2016-10-03
 +* Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
 +* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
 +  allowed by default.
 +* New lint: [`explicit_into_iter_loop`]
 +
 +## 0.0.92 — 2016-09-30
 +* Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
 +
 +## 0.0.91 — 2016-09-28
 +* Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
 +
 +## 0.0.90 — 2016-09-09
 +* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
 +
 +## 0.0.89 — 2016-09-06
 +* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
 +
 +## 0.0.88 — 2016-09-04
 +* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
 +* The following lints are not new but were only usable through the `clippy`
 +  lint groups: [`filter_next`], `for_loop_over_option`,
 +  `for_loop_over_result` and [`match_overlapping_arm`]. You should now be
 +  able to `#[allow/deny]` them individually and they are available directly
 +  through `cargo clippy`.
 +
 +## 0.0.87 — 2016-08-31
 +* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
 +* New lints: [`builtin_type_shadow`]
 +* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
 +
 +## 0.0.86 — 2016-08-28
 +* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
 +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
 +
 +## 0.0.85 — 2016-08-19
 +* Fix ICE with [`useless_attribute`]
 +* [`useless_attribute`] ignores `unused_imports` on `use` statements
 +
 +## 0.0.84 — 2016-08-18
 +* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
 +
 +## 0.0.83 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
 +* New lints: [`print_with_newline`], [`useless_attribute`]
 +
 +## 0.0.82 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
 +* New lint: [`module_inception`]
 +
 +## 0.0.81 — 2016-08-14
 +* Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
 +* New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
 +* False positive fix in [`too_many_arguments`]
 +* Addition of functionality to [`needless_borrow`]
 +* Suggestions for [`clone_on_copy`]
 +* Bug fix in [`wrong_self_convention`]
 +* Doc improvements
 +
 +## 0.0.80 — 2016-07-31
 +* Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
 +* New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
 +
 +## 0.0.79 — 2016-07-10
 +* Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
 +* Major suggestions refactoring
 +
 +## 0.0.78 — 2016-07-02
 +* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
 +* New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
 +* For compatibility, `cargo clippy` does not defines the `clippy` feature
 +  introduced in 0.0.76 anymore
 +* [`collapsible_if`] now considers `if let`
 +
 +## 0.0.77 — 2016-06-21
 +* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
 +* New lints: `stutter` and [`iter_nth`]
 +
 +## 0.0.76 — 2016-06-10
 +* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
 +* `cargo clippy` now automatically defines the `clippy` feature
 +* New lint: [`not_unsafe_ptr_arg_deref`]
 +
 +## 0.0.75 — 2016-06-08
 +* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
 +
 +## 0.0.74 — 2016-06-07
 +* Fix bug with `cargo-clippy` JSON parsing
 +* Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
 +  “for further information visit *lint-link*” message.
 +
 +## 0.0.73 — 2016-06-05
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.72 — 2016-06-04
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.71 — 2016-05-31
 +* Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
 +* New lint: [`useless_let_if_seq`]
 +
 +## 0.0.70 — 2016-05-28
 +* Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
 +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
 +  `RegexBuilder::new` and byte regexes
 +
 +## 0.0.69 — 2016-05-20
 +* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
 +* [`used_underscore_binding`] has been made `Allow` temporarily
 +
 +## 0.0.68 — 2016-05-17
 +* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
 +* New lint: [`unnecessary_operation`]
 +
 +## 0.0.67 — 2016-05-12
 +* Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
 +
 +## 0.0.66 — 2016-05-11
 +* New `cargo clippy` subcommand
 +* New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
 +
 +## 0.0.65 — 2016-05-08
 +* Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
 +* New lints: [`float_arithmetic`], [`integer_arithmetic`]
 +
 +## 0.0.64 — 2016-04-26
 +* Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
 +* New lints: [`temporary_cstring_as_ptr`], [`unsafe_removed_from_name`], and [`mem_forget`]
 +
 +## 0.0.63 — 2016-04-08
 +* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
 +
 +## 0.0.62 — 2016-04-07
 +* Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
 +
 +## 0.0.61 — 2016-04-03
 +* Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
 +* New lint: [`invalid_upcast_comparisons`]
 +
 +## 0.0.60 — 2016-04-01
 +* Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
 +
 +## 0.0.59 — 2016-03-31
 +* Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
 +* New lints: [`logic_bug`], [`nonminimal_bool`]
 +* Fixed: [`match_same_arms`] now ignores arms with guards
 +* Improved: [`useless_vec`] now warns on `for … in vec![…]`
 +
 +## 0.0.58 — 2016-03-27
 +* Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
 +* New lint: [`doc_markdown`]
 +
 +## 0.0.57 — 2016-03-27
 +* Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
 +* Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
 +* New lint: [`crosspointer_transmute`]
 +
 +## 0.0.56 — 2016-03-23
 +* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
 +* New lints: [`many_single_char_names`] and [`similar_names`]
 +
 +## 0.0.55 — 2016-03-21
 +* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
 +
 +## 0.0.54 — 2016-03-16
 +* Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
 +
 +## 0.0.53 — 2016-03-15
 +* Add a [configuration file]
 +
 +## ~~0.0.52~~
 +
 +## 0.0.51 — 2016-03-13
 +* Add `str` to types considered by [`len_zero`]
 +* New lints: [`indexing_slicing`]
 +
 +## 0.0.50 — 2016-03-11
 +* Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
 +
 +## 0.0.49 — 2016-03-09
 +* Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
 +* New lints: [`overflow_check_conditional`], [`unused_label`], [`new_without_default`]
 +
 +## 0.0.48 — 2016-03-07
 +* Fixed: ICE in [`needless_range_loop`] with globals
 +
 +## 0.0.47 — 2016-03-07
 +* Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
 +* New lint: [`redundant_closure_call`]
 +
 +[`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html
 +[`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
 +[configuration file]: ./rust-clippy#configuration
 +[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +
 +<!-- lint disable no-unused-definitions -->
 +<!-- begin autogenerated links to lint list -->
 +[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 +[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 +[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 +[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 +[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 +[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
 +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
 +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 +[`await_holding_refcell_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_refcell_ref
 +[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 +[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 +[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
 +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 +[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 +[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 +[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 +[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 +[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
 +[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 +[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 +[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
 +[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
 +[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 +[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 +[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 +[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
 +[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 +[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 +[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 +[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 +[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
 +[`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions
 +[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
 +[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
 +[`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
 +[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 +[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 +[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
 +[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 +[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 +[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 +[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 +[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 +[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 +[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 +[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 +[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
 +[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
 +[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 +[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 +[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 +[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 +[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 +[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 +[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 +[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 +[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 +[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 +[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
 +[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 +[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 +[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 +[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
 +[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
 +[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
 +[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
 +[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
 +[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
 +[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
 +[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 +[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 +[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
 +[`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
 +[`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_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 +[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
 +[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
 +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
 +[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
 +[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
 +[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 +[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 +[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 +[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
 +[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 +[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 +[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
 +[`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
 +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 +[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 +[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 +[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 +[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 +[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 +[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
 +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 +[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 +[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
 +[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
 +[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
 +[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
 +[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
 +[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 +[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 +[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
 +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
 +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
 +[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`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_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 +[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 +[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 +[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
 +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
 +[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
 +[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
 +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 +[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
 +[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 +[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 +[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
 +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
 +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
 +[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 +[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 +[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 +[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 +[`manual_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_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_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
 +[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 +[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
 +[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 +[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 +[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 +[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 +[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 +[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 +[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 +[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
 +[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
++[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 +[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 +[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 +[`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_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 +[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 +[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 +[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 +[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 +[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 +[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 +[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 +[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 +[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
 +[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
 +[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 +[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 +[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
 +[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 +[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
 +[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 +[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 +[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
 +[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
 +[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 +[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 +[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 +[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 +[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 +[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 +[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 +[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 +[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
 +[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
 +[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 +[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 +[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 +[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 +[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 +[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 +[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
 +[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 +[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 +[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 +[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
 +[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
 +[`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_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_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 +[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 +[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 +[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 +[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 +[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 +[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 +[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 +[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 +[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
 +[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 +[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 +[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 +[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 +[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 +[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 +[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 +[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 +[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 +[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 +[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 +[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
 +[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 +[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`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_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 +[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 +[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 +[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 +[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 +[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 +[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 +[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
 +[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 +[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 +[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 +[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 +[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 +[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
 +[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 +[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 +[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 +[`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 +[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
 +[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
 +[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 +[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 +[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
 +[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 +[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 +[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
 +[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
 +[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
 +[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 +[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 +[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 +[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`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_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 +[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
 +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 +[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 +[`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_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 f2641a23f563b0528be459163f3568057ff93aed,0000000000000000000000000000000000000000..5954ab25d194234539ec255b21520d480b00cc23
mode 100644,000000..100644
--- /dev/null
@@@ -1,358 -1,0 +1,359 @@@
- All issues on Clippy are mentored, if you want help with a bug just ask
- @Manishearth, @flip1995, @phansch or @yaahc.
 +# Contributing to Clippy
 +
 +Hello fellow Rustacean! Great to see your interest in compiler internals and lints!
 +
 +**First**: if you're unsure or afraid of _anything_, just ask or submit the issue or pull request anyway. You won't be
 +yelled at for giving it your best effort. The worst that can happen is that you'll be politely asked to change
 +something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
 +
 +Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
 +explains how you can contribute and how to get started.  If you have any questions about contributing or need help with
 +anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip].
 +
 +All contributors are expected to follow the [Rust Code of Conduct].
 +
 +- [Contributing to Clippy](#contributing-to-clippy)
 +  - [Getting started](#getting-started)
 +    - [High level approach](#high-level-approach)
 +    - [Finding something to fix/improve](#finding-something-to-fiximprove)
 +  - [Writing code](#writing-code)
 +  - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work)
 +  - [How Clippy works](#how-clippy-works)
 +  - [Syncing changes between Clippy and `rust-lang/rust`](#syncing-changes-between-clippy-and-rust-langrust)
 +    - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos)
 +    - [Performing the sync from `rust-lang/rust` to Clippy](#performing-the-sync-from-rust-langrust-to-clippy)
 +    - [Performing the sync from Clippy to `rust-lang/rust`](#performing-the-sync-from-clippy-to-rust-langrust)
 +    - [Defining remotes](#defining-remotes)
 +  - [Issue and PR triage](#issue-and-pr-triage)
 +  - [Bors and Homu](#bors-and-homu)
 +  - [Contributions](#contributions)
 +
 +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
 +[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
 +
 +## Getting started
 +
 +**Note: If this is your first time contributing to Clippy, you should
 +first read the [Basics docs](doc/basics.md).**
 +
 +### High level approach
 +
 +1. Find something to fix/improve
 +2. Change code (likely some file in `clippy_lints/src/`)
 +3. Follow the instructions in the [Basics docs](doc/basics.md) to get set up
 +4. Run `cargo test` in the root directory and wiggle code until it passes
 +5. Open a PR (also can be done after 2. if you run into problems)
 +
 +### Finding something to fix/improve
 +
- Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues.
- If you want to work on an issue, please leave a comment so that we can assign it to you!
++All issues on Clippy are mentored, if you want help simply ask @Manishearth, @flip1995, @phansch
++or @llogiq directly by mentioning them in the issue or over on [Zulip]. This list may be out of date.
++All currently active mentors can be found [here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3)
 +
++Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy
++issues. You can use `@rustbot claim` to assign the issue to yourself.
 +
 +There are also some abandoned PRs, marked with [`S-inactive-closed`].
 +Pretty often these PRs are nearly completed and just need some extra steps
 +(formatting, addressing review comments, ...) to be merged. If you want to
 +complete such a PR, please leave a comment in the PR and open a new one based
 +on it.
 +
 +Issues marked [`T-AST`] involve simple matching of the syntax tree structure,
 +and are generally easier than [`T-middle`] issues, which involve types
 +and resolved paths.
 +
 +[`T-AST`] issues will generally need you to match against a predefined syntax structure.
 +To figure out how this syntax structure is encoded in the AST, it is recommended to run
 +`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs].
 +Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 +But we can make it nest-less by using [if_chain] macro, [like this][nest-less].
 +
 +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
 +first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
 +Note that [`E-medium`] issues may require some knowledge of Clippy internals or some
 +debugging to find the actual problem behind the issue.
 +
 +[`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
 +lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
 +an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
 +
 +[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
 +[`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
 +[`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
 +[`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
 +[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
 +[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
 +[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
 +[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
 +[if_chain]: https://docs.rs/if_chain/*/if_chain
 +[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150
 +
 +## Writing code
 +
 +Have a look at the [docs for writing lints][adding_lints] for more details.
 +
 +If you want to add a new lint or change existing ones apart from bugfixing, it's
 +also a good idea to give the [stability guarantees][rfc_stability] and
 +[lint categories][rfc_lint_cats] sections of the [Clippy 1.0 RFC][clippy_rfc] a
 +quick read.
 +
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
 +[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
 +[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
 +
 +## Getting code-completion for rustc internals to work
 +
 +Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals
 +using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not
 +available via a `rustup` component at the time of writing.
 +To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via
 +`git clone https://github.com/rust-lang/rust/`.
 +Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies
 +which rust-analyzer will be able to understand.
 +Run `cargo dev ra_setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo
 +you just cloned.
 +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
 +Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses.
 +Just make sure to remove the dependencies again before finally making a pull request!
 +
 +[ra_homepage]: https://rust-analyzer.github.io/
 +[rustc_repo]: https://github.com/rust-lang/rust/
 +
 +## How Clippy works
 +
 +[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`].
 +For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this:
 +
 +```rust
 +// ./clippy_lints/src/lib.rs
 +
 +// ...
 +pub mod else_if_without_else;
 +// ...
 +
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    // ...
 +    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
 +    // ...
 +
 +    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +        // ...
 +        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +        // ...
 +    ]);
 +}
 +```
 +
 +The [`rustc_lint::LintStore`][`LintStore`] provides two methods to register lints:
 +[register_early_pass][reg_early_pass] and [register_late_pass][reg_late_pass]. Both take an object
 +that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in
 +every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev
 +update_lints`. When you are writing your own lint, you can use that script to save you some time.
 +
 +```rust
 +// ./clippy_lints/src/else_if_without_else.rs
 +
 +use rustc_lint::{EarlyLintPass, EarlyContext};
 +
 +// ...
 +
 +pub struct ElseIfWithoutElse;
 +
 +// ...
 +
 +impl EarlyLintPass for ElseIfWithoutElse {
 +    // ... the functions needed, to make the lint work
 +}
 +```
 +
 +The difference between `EarlyLintPass` and `LateLintPass` is that the methods of the `EarlyLintPass` trait only provide
 +AST information. The methods of the `LateLintPass` trait are executed after type checking and contain type information
 +via the `LateContext` parameter.
 +
 +That's why the `else_if_without_else` example uses the `register_early_pass` function. Because the
 +[actual lint logic][else_if_without_else] does not depend on any type information.
 +
 +[lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
 +[else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/4253aa7137cb7378acc96133c787e49a345c2b3c/clippy_lints/src/else_if_without_else.rs
 +[`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html
 +[reg_early_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_early_pass
 +[reg_late_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_late_pass
 +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
 +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
 +
 +## Syncing changes between Clippy and [`rust-lang/rust`]
 +
 +Clippy currently gets built with a pinned nightly version.
 +
 +In the `rust-lang/rust` repository, where rustc resides, there's a copy of Clippy
 +that compiler hackers modify from time to time to adapt to changes in the unstable
 +API of the compiler.
 +
 +We need to sync these changes back to this repository periodically, and the changes
 +made to this repository in the meantime also need to be synced to the `rust-lang/rust` repository.
 +
 +To avoid flooding the `rust-lang/rust` PR queue, this two-way sync process is done
 +in a bi-weekly basis if there's no urgent changes. This is done starting on the day of
 +the Rust stable release and then every other week. That way we guarantee that we keep
 +this repo up to date with the latest compiler API, and every feature in Clippy is available
 +for 2 weeks in nightly, before it can get to beta. For reference, the first sync
 +following this cadence was performed the 2020-08-27.
 +
 +This process is described in detail in the following sections. For general information
 +about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree].
 +
 +### Patching git-subtree to work with big repos
 +
 +Currently there's a bug in `git-subtree` that prevents it from working properly
 +with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale.
 +Before continuing with the following steps, we need to manually apply that fix to
 +our local copy of `git-subtree`.
 +
 +You can get the patched version of `git-subtree` from [here][gitgitgadget-pr].
 +Put this file under `/usr/lib/git-core` (taking a backup of the previous file)
 +and make sure it has the proper permissions:
 +
 +```bash
 +sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
 +sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +```
 +
 +_Note:_ The first time running `git subtree push` a cache has to be built. This
 +involves going through the complete Clippy history once. For this you have to
 +increase the stack limit though, which you can do with `ulimit -s 60000`.
 +Make sure to run the `ulimit` command from the same session you call git subtree.
 +
 +_Note:_ If you are a Debian user, `dash` is the shell used by default for scripts instead of `sh`.
 +This shell has a hardcoded recursion limit set to 1000. In order to make this process work,
 +you need to force the script to run `bash` instead. You can do this by editing the first
 +line of the `git-subtree` script and changing `sh` to `bash`.
 +
 +### Performing the sync from [`rust-lang/rust`] to Clippy
 +
 +Here is a TL;DR version of the sync process (all of the following commands have
 +to be run inside the `rust` directory):
 +
 +1. Clone the [`rust-lang/rust`] repository or make sure it is up to date.
 +2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
 +3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
 +    ```bash
 +    # Make sure to change `your-github-name` to your github name in the following command
 +    git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
 +    ```
 +
 +    _Note:_ This will directly push to the remote repository. You can also push
 +    to your local copy by replacing the remote address with `/path/to/rust-clippy`
 +    directory.
 +
 +    _Note:_ Most of the time you have to create a merge commit in the
 +    `rust-clippy` repo (this has to be done in the Clippy repo, not in the
 +    rust-copy of Clippy):
 +    ```bash
 +    git fetch origin && git fetch upstream
 +    git checkout sync-from-rust
 +    git merge upstream/master
 +    ```
 +4. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
 +   accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
 +   ~~annoy~~ ask them in the [Zulip] stream.)
 +
 +### Performing the sync from Clippy to [`rust-lang/rust`]
 +
 +All of the following commands have to be run inside the `rust` directory.
 +
 +1. Make sure Clippy itself is up-to-date by following the steps outlined in the previous
 +section if necessary.
 +
 +2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy:
 +    ```bash
 +    git checkout -b sync-from-clippy
 +    git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master
 +    ```
 +3. Open a PR to [`rust-lang/rust`]
 +
 +### Defining remotes
 +
 +You may want to define remotes, so you don't have to type out the remote
 +addresses on every sync. You can do this with the following commands (these
 +commands still have to be run inside the `rust` directory):
 +
 +```bash
 +# Set clippy-upstream remote for pulls
 +$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy
 +# Make sure to not push to the upstream repo
 +$ git remote set-url --push clippy-upstream DISABLED
 +# Set clippy-origin remote to your fork for pushes
 +$ git remote add clippy-origin git@github.com:your-github-name/rust-clippy
 +# Set a local remote
 +$ git remote add clippy-local /path/to/rust-clippy
 +```
 +
 +You can then sync with the remote names from above, e.g.:
 +
 +```bash
 +$ git subtree push -P src/tools/clippy clippy-local sync-from-rust
 +```
 +
 +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493
 +[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree
 +[`rust-lang/rust`]: https://github.com/rust-lang/rust
 +
 +## Issue and PR triage
 +
 +Clippy is following the [Rust triage procedure][triage] for issues and pull
 +requests.
 +
 +However, we are a smaller project with all contributors being volunteers
 +currently. Between writing new lints, fixing issues, reviewing pull requests and
 +responding to issues there may not always be enough time to stay on top of it
 +all.
 +
 +Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example
 +an ICE in a popular crate that many other crates depend on. We don't
 +want Clippy to crash on your code and we want it to be as reliable as the
 +suggestions from Rust compiler errors.
 +
 +We have prioritization labels and a sync-blocker label, which are described below.
 +- [P-low][p-low]: Requires attention (fix/response/evaluation) by a team member but isn't urgent.
 +- [P-medium][p-medium]: Should be addressed by a team member until the next sync.
 +- [P-high][p-high]: Should be immediately addressed and will require an out-of-cycle sync or a backport.
 +- [L-sync-blocker][l-sync-blocker]: An issue that "blocks" a sync. 
 +Or rather: before the sync this should be addressed,
 +e.g. by removing a lint again, so it doesn't hit beta/stable.
 +
 +## Bors and Homu
 +
 +We use a bot powered by [Homu][homu] to help automate testing and landing of pull
 +requests in Clippy. The bot's username is @bors.
 +
 +You can find the Clippy bors queue [here][homu_queue].
 +
 +If you have @bors permissions, you can find an overview of the available
 +commands [here][homu_instructions].
 +
 +[triage]: https://forge.rust-lang.org/release/triage-procedure.html
 +[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash
 +[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug
 +[p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low
 +[p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium
 +[p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high
 +[l-sync-blocker]: https://github.com/rust-lang/rust-clippy/labels/L-sync-blocker
 +[homu]: https://github.com/rust-lang/homu
 +[homu_instructions]: https://bors.rust-lang.org/
 +[homu_queue]: https://bors.rust-lang.org/queue/clippy
 +
 +## Contributions
 +
 +Contributions to Clippy should be made in the form of GitHub pull requests. Each pull request will
 +be reviewed by a core contributor (someone with permission to land patches) and either landed in the
 +main tree or given feedback for changes that would be required.
 +
 +All code in this repository is under the [Apache-2.0] or the [MIT] license.
 +
 +<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
 +
 +[Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0
 +[MIT]: https://opensource.org/licenses/MIT
index b877806946cfeb0435b5d348368ff3505e2cb414,0000000000000000000000000000000000000000..2a869e9d4491b6805a332495fd753b886a1c821e
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,102 @@@
 +//! `bless` updates the reference files in the repo with changed output files
 +//! from the last test run.
 +
 +use std::env;
 +use std::ffi::OsStr;
 +use std::fs;
 +use std::lazy::SyncLazy;
 +use std::path::{Path, PathBuf};
 +use walkdir::WalkDir;
 +
 +use crate::clippy_project_root;
 +
 +// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
 +pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
 +    Some(v) => v.into(),
 +    None => env::current_dir().unwrap().join("target"),
 +});
 +
 +static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
 +    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
 +    let mut path = PathBuf::from(&**CARGO_TARGET_DIR);
 +    path.push(profile);
 +    path.push("cargo-clippy");
 +    fs::metadata(path).ok()?.modified().ok()
 +});
 +
++/// # Panics
++///
++/// Panics if the path to a test file is broken
 +pub fn bless(ignore_timestamp: bool) {
 +    let test_suite_dirs = [
 +        clippy_project_root().join("tests").join("ui"),
 +        clippy_project_root().join("tests").join("ui-internal"),
 +        clippy_project_root().join("tests").join("ui-toml"),
 +        clippy_project_root().join("tests").join("ui-cargo"),
 +    ];
 +    for test_suite_dir in &test_suite_dirs {
 +        WalkDir::new(test_suite_dir)
 +            .into_iter()
 +            .filter_map(Result::ok)
 +            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
 +            .for_each(|f| {
 +                let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
 +                for &ext in &["stdout", "stderr", "fixed"] {
 +                    update_reference_file(
 +                        f.path().with_extension(ext),
 +                        test_name.with_extension(ext),
 +                        ignore_timestamp,
 +                    );
 +                }
 +            });
 +    }
 +}
 +
 +fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) {
 +    let test_output_path = build_dir().join(test_name);
 +    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
 +
 +    // If compiletest did not write any changes during the test run,
 +    // we don't have to update anything
 +    if !test_output_path.exists() {
 +        return;
 +    }
 +
 +    // 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_path).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 {}", &relative_reference_file_path.display());
 +        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
 +
 +        // We need to re-read the file now because it was potentially updated from copying
 +        let reference_file = fs::read(&reference_file_path).unwrap_or_default();
 +
 +        if reference_file.is_empty() {
 +            // If we copied over an empty output file, we remove the now empty reference file
 +            println!("removing {}", &relative_reference_file_path.display());
 +            fs::remove_file(reference_file_path).expect("Could not remove reference file");
 +        }
 +    }
 +}
 +
 +fn updated_since_clippy_build(path: &Path) -> Option<bool> {
 +    let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
 +    let modified = fs::metadata(path).ok()?.modified().ok()?;
 +    Some(modified >= clippy_build_time)
 +}
 +
 +fn build_dir() -> PathBuf {
 +    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
 +    let mut path = PathBuf::new();
 +    path.push(CARGO_TARGET_DIR.clone());
 +    path.push(profile);
 +    path.push("test_build_base");
 +    path
 +}
index 6b528d219df27d62a37f859f0900f3f6402b2b58,0000000000000000000000000000000000000000..4d0fdadbd85d184d6b927db81211764c729e5153
mode 100644,000000..100644
--- /dev/null
@@@ -1,194 -1,0 +1,201 @@@
-     CommandFailed(String),
 +use crate::clippy_project_root;
 +use shell_escape::escape;
 +use std::ffi::OsStr;
 +use std::path::Path;
 +use std::process::{self, Command};
 +use std::{fs, io};
 +use walkdir::WalkDir;
 +
 +#[derive(Debug)]
 +pub enum CliError {
-             CliError::CommandFailed(command) => {
-                 eprintln!("error: A command failed! `{}`", command);
++    CommandFailed(String, String),
 +    IoError(io::Error),
 +    RustfmtNotInstalled,
 +    WalkDirError(walkdir::Error),
 +    RaSetupActive,
 +}
 +
 +impl From<io::Error> for CliError {
 +    fn from(error: io::Error) -> Self {
 +        Self::IoError(error)
 +    }
 +}
 +
 +impl From<walkdir::Error> for CliError {
 +    fn from(error: walkdir::Error) -> Self {
 +        Self::WalkDirError(error)
 +    }
 +}
 +
 +struct FmtContext {
 +    check: bool,
 +    verbose: bool,
 +}
 +
 +// the "main" function of cargo dev fmt
 +pub fn run(check: bool, verbose: bool) {
 +    fn try_run(context: &FmtContext) -> Result<bool, CliError> {
 +        let mut success = true;
 +
 +        let project_root = clippy_project_root();
 +
 +        // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
 +        // format because rustfmt would also format the entire rustc repo as it is a local
 +        // dependency
 +        if fs::read_to_string(project_root.join("Cargo.toml"))
 +            .expect("Failed to read clippy Cargo.toml")
 +            .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
 +        {
 +            return Err(CliError::RaSetupActive);
 +        }
 +
 +        rustfmt_test(context)?;
 +
 +        success &= cargo_fmt(context, project_root.as_path())?;
 +        success &= cargo_fmt(context, &project_root.join("clippy_dev"))?;
 +        success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
 +
 +        for entry in WalkDir::new(project_root.join("tests")) {
 +            let entry = entry?;
 +            let path = entry.path();
 +
 +            if path.extension() != Some("rs".as_ref())
 +                || entry.file_name() == "ice-3891.rs"
 +                // Avoid rustfmt bug rust-lang/rustfmt#1873
 +                || cfg!(windows) && entry.file_name() == "implicit_hasher.rs"
 +            {
 +                continue;
 +            }
 +
 +            success &= rustfmt(context, &path)?;
 +        }
 +
 +        Ok(success)
 +    }
 +
 +    fn output_err(err: CliError) {
 +        match err {
-     let mut child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
-     let code = child.wait()?;
-     let success = code.success();
++            CliError::CommandFailed(command, stderr) => {
++                eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr);
 +            },
 +            CliError::IoError(err) => {
 +                eprintln!("error: {}", err);
 +            },
 +            CliError::RustfmtNotInstalled => {
 +                eprintln!("error: rustfmt nightly is not installed.");
 +            },
 +            CliError::WalkDirError(err) => {
 +                eprintln!("error: {}", err);
 +            },
 +            CliError::RaSetupActive => {
 +                eprintln!(
 +                    "error: a local rustc repo is enabled as path dependency via `cargo dev ra_setup`.
 +Not formatting because that would format the local repo as well!
 +Please revert the changes to Cargo.tomls first."
 +                );
 +            },
 +        }
 +    }
 +
 +    let context = FmtContext { check, verbose };
 +    let result = try_run(&context);
 +    let code = match result {
 +        Ok(true) => 0,
 +        Ok(false) => {
 +            eprintln!();
 +            eprintln!("Formatting check failed.");
 +            eprintln!("Run `cargo dev fmt` to update formatting.");
 +            1
 +        },
 +        Err(err) => {
 +            output_err(err);
 +            1
 +        },
 +    };
 +    process::exit(code);
 +}
 +
 +fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
 +    let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect();
 +
 +    format!(
 +        "cd {} && {} {}",
 +        escape(dir.as_ref().to_string_lossy()),
 +        escape(program.as_ref().to_string_lossy()),
 +        arg_display.join(" ")
 +    )
 +}
 +
 +fn exec(
 +    context: &FmtContext,
 +    program: impl AsRef<OsStr>,
 +    dir: impl AsRef<Path>,
 +    args: &[impl AsRef<OsStr>],
 +) -> Result<bool, CliError> {
 +    if context.verbose {
 +        println!("{}", format_command(&program, &dir, args));
 +    }
 +
-         return Err(CliError::CommandFailed(format_command(&program, &dir, args)));
++    let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
++    let output = child.wait_with_output()?;
++    let success = output.status.success();
 +
 +    if !context.check && !success {
-         Err(CliError::CommandFailed(format_command(&program, &dir, args)))
++        let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
++        return Err(CliError::CommandFailed(
++            format_command(&program, &dir, args),
++            String::from(stderr),
++        ));
 +    }
 +
 +    Ok(success)
 +}
 +
 +fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
 +    let mut args = vec!["+nightly", "fmt", "--all"];
 +    if context.check {
 +        args.push("--");
 +        args.push("--check");
 +    }
 +    let success = exec(context, "cargo", path, &args)?;
 +
 +    Ok(success)
 +}
 +
 +fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
 +    let program = "rustfmt";
 +    let dir = std::env::current_dir()?;
 +    let args = &["+nightly", "--version"];
 +
 +    if context.verbose {
 +        println!("{}", format_command(&program, &dir, args));
 +    }
 +
 +    let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;
 +
 +    if output.status.success() {
 +        Ok(())
 +    } else if std::str::from_utf8(&output.stderr)
 +        .unwrap_or("")
 +        .starts_with("error: 'rustfmt' is not installed")
 +    {
 +        Err(CliError::RustfmtNotInstalled)
 +    } else {
++        Err(CliError::CommandFailed(
++            format_command(&program, &dir, args),
++            std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
++        ))
 +    }
 +}
 +
 +fn rustfmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
 +    let mut args = vec!["+nightly".as_ref(), path.as_os_str()];
 +    if context.check {
 +        args.push("--check".as_ref());
 +    }
 +    let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
 +    if !success {
 +        eprintln!("rustfmt failed on {}", path.display());
 +    }
 +    Ok(success)
 +}
index 24d70d433f367e0072def9923508bb5a2b125c60,0000000000000000000000000000000000000000..01d1fc9211a94fc2576f26786df87e64485824df
mode 100644,000000..100644
--- /dev/null
@@@ -1,546 -1,0 +1,559 @@@
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![feature(once_cell)]
 +
 +use itertools::Itertools;
 +use regex::Regex;
 +use std::collections::HashMap;
 +use std::ffi::OsStr;
 +use std::fs;
 +use std::lazy::SyncLazy;
 +use std::path::{Path, PathBuf};
 +use walkdir::WalkDir;
 +
 +pub mod bless;
 +pub mod fmt;
 +pub mod lintcheck;
 +pub mod new_lint;
 +pub mod ra_setup;
 +pub mod serve;
 +pub mod stderr_length_check;
 +pub mod update_lints;
 +
 +static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
 +    Regex::new(
 +        r#"(?x)
 +    declare_clippy_lint!\s*[\{(]
 +    (?:\s+///.*)*
 +    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
 +    (?P<cat>[a-z_]+)\s*,\s*
 +    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
 +"#,
 +    )
 +    .unwrap()
 +});
 +
 +static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
 +    Regex::new(
 +        r#"(?x)
 +    declare_deprecated_lint!\s*[{(]\s*
 +    (?:\s+///.*)*
 +    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
 +    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
 +"#,
 +    )
 +    .unwrap()
 +});
 +static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
 +
 +pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
 +
 +/// Lint data parsed from the Clippy source code.
 +#[derive(Clone, PartialEq, Debug)]
 +pub struct Lint {
 +    pub name: String,
 +    pub group: String,
 +    pub desc: String,
 +    pub deprecation: Option<String>,
 +    pub module: String,
 +}
 +
 +impl Lint {
 +    #[must_use]
 +    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
 +        Self {
 +            name: name.to_lowercase(),
 +            group: group.to_string(),
 +            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
 +            deprecation: deprecation.map(ToString::to_string),
 +            module: module.to_string(),
 +        }
 +    }
 +
 +    /// Returns all non-deprecated lints and non-internal lints
 +    #[must_use]
 +    pub fn usable_lints(lints: &[Self]) -> Vec<Self> {
 +        lints
 +            .iter()
 +            .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal"))
 +            .cloned()
 +            .collect()
 +    }
 +
 +    /// Returns all internal lints (not `internal_warn` lints)
 +    #[must_use]
 +    pub fn internal_lints(lints: &[Self]) -> Vec<Self> {
 +        lints.iter().filter(|l| l.group == "internal").cloned().collect()
 +    }
 +
 +    /// Returns all deprecated lints
 +    #[must_use]
 +    pub fn deprecated_lints(lints: &[Self]) -> Vec<Self> {
 +        lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect()
 +    }
 +
 +    /// Returns the lints in a `HashMap`, grouped by the different lint groups
 +    #[must_use]
 +    pub fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
 +        lints.map(|lint| (lint.group.to_string(), lint)).into_group_map()
 +    }
 +}
 +
 +/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
 +#[must_use]
 +pub fn gen_lint_group_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
 +    lints
 +        .map(|l| format!("        LintId::of(&{}::{}),", l.module, l.name.to_uppercase()))
 +        .sorted()
 +        .collect::<Vec<String>>()
 +}
 +
 +/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
 +#[must_use]
 +pub fn gen_modules_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
 +    lints
 +        .map(|l| &l.module)
 +        .unique()
 +        .map(|module| format!("mod {};", module))
 +        .sorted()
 +        .collect::<Vec<String>>()
 +}
 +
 +/// Generates the list of lint links at the bottom of the README
 +#[must_use]
 +pub fn gen_changelog_lint_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
 +    lints
 +        .sorted_by_key(|l| &l.name)
 +        .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name))
 +        .collect()
 +}
 +
 +/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
 +#[must_use]
 +pub fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
 +    lints
 +        .flat_map(|l| {
 +            l.deprecation
 +                .clone()
 +                .map(|depr_text| {
 +                    vec![
 +                        "    store.register_removed(".to_string(),
 +                        format!("        \"clippy::{}\",", l.name),
 +                        format!("        \"{}\",", depr_text),
 +                        "    );".to_string(),
 +                    ]
 +                })
 +                .expect("only deprecated lints should be passed")
 +        })
 +        .collect::<Vec<String>>()
 +}
 +
 +#[must_use]
 +pub fn gen_register_lint_list<'a>(
 +    internal_lints: impl Iterator<Item = &'a Lint>,
 +    usable_lints: impl Iterator<Item = &'a Lint>,
 +) -> Vec<String> {
 +    let header = "    store.register_lints(&[".to_string();
 +    let footer = "    ]);".to_string();
 +    let internal_lints = internal_lints
 +        .sorted_by_key(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
 +        .map(|l| {
 +            format!(
 +                "        #[cfg(feature = \"internal-lints\")]\n        &{}::{},",
 +                l.module,
 +                l.name.to_uppercase()
 +            )
 +        });
 +    let other_lints = usable_lints
 +        .sorted_by_key(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
 +        .map(|l| format!("        &{}::{},", l.module, l.name.to_uppercase()))
 +        .sorted();
 +    let mut lint_list = vec![header];
 +    lint_list.extend(internal_lints);
 +    lint_list.extend(other_lints);
 +    lint_list.push(footer);
 +    lint_list
 +}
 +
 +/// Gathers all files in `src/clippy_lints` and gathers all lints inside
 +pub fn gather_all() -> impl Iterator<Item = Lint> {
 +    lint_files().flat_map(|f| gather_from_file(&f))
 +}
 +
 +fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item = Lint> {
 +    let content = fs::read_to_string(dir_entry.path()).unwrap();
 +    let path = dir_entry.path();
 +    let filename = path.file_stem().unwrap();
 +    let path_buf = path.with_file_name(filename);
 +    let mut rel_path = path_buf
 +        .strip_prefix(clippy_project_root().join("clippy_lints/src"))
 +        .expect("only files in `clippy_lints/src` should be looked at");
 +    // If the lints are stored in mod.rs, we get the module name from
 +    // the containing directory:
 +    if filename == "mod" {
 +        rel_path = rel_path.parent().unwrap();
 +    }
 +
 +    let module = rel_path
 +        .components()
 +        .map(|c| c.as_os_str().to_str().unwrap())
 +        .collect::<Vec<_>>()
 +        .join("::");
 +
 +    parse_contents(&content, &module)
 +}
 +
 +fn parse_contents(content: &str, module: &str) -> impl Iterator<Item = Lint> {
 +    let lints = DEC_CLIPPY_LINT_RE
 +        .captures_iter(content)
 +        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module));
 +    let deprecated = DEC_DEPRECATED_LINT_RE
 +        .captures_iter(content)
 +        .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module));
 +    // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
 +    lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
 +}
 +
 +/// Collects all .rs files in the `clippy_lints/src` directory
 +fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> {
 +    // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
 +    // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
 +    let path = clippy_project_root().join("clippy_lints/src");
 +    WalkDir::new(path)
 +        .into_iter()
 +        .filter_map(Result::ok)
 +        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
 +}
 +
 +/// Whether a file has had its text changed or not
 +#[derive(PartialEq, Debug)]
 +pub struct FileChange {
 +    pub changed: bool,
 +    pub new_lines: String,
 +}
 +
 +/// Replaces a region in a file delimited by two lines matching regexes.
 +///
 +/// `path` is the relative path to the file on which you want to perform the replacement.
 +///
 +/// See `replace_region_in_text` for documentation of the other options.
++///
++/// # Panics
++///
++/// Panics if the path could not read or then written
 +pub fn replace_region_in_file<F>(
 +    path: &Path,
 +    start: &str,
 +    end: &str,
 +    replace_start: bool,
 +    write_back: bool,
 +    replacements: F,
 +) -> FileChange
 +where
 +    F: FnOnce() -> Vec<String>,
 +{
 +    let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e));
 +    let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
 +
 +    if write_back {
 +        if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) {
 +            panic!("Cannot write to {}: {}", path.display(), e);
 +        }
 +    }
 +    file_change
 +}
 +
 +/// Replaces a region in a text delimited by two lines matching regexes.
 +///
 +/// * `text` is the input text on which you want to perform the replacement
 +/// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
 +///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
 +/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
 +///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
 +/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end`
 +///   delimiter line is never replaced.
 +/// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
 +///
 +/// If you want to perform the replacement on files instead of already parsed text,
 +/// use `replace_region_in_file`.
 +///
 +/// # Example
 +///
 +/// ```
 +/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
 +/// let result =
 +///     clippy_dev::replace_region_in_text(the_text, "replace_start", "replace_end", false, || {
 +///         vec!["a different".to_string(), "text".to_string()]
 +///     })
 +///     .new_lines;
 +/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
 +/// ```
++///
++/// # Panics
++///
++/// Panics if start or end is not valid regex
 +pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange
 +where
 +    F: FnOnce() -> Vec<String>,
 +{
 +    let replace_it = replacements();
 +    let mut in_old_region = false;
 +    let mut found = false;
 +    let mut new_lines = vec![];
 +    let start = Regex::new(start).unwrap();
 +    let end = Regex::new(end).unwrap();
 +
 +    for line in text.lines() {
 +        if in_old_region {
 +            if end.is_match(line) {
 +                in_old_region = false;
 +                new_lines.extend(replace_it.clone());
 +                new_lines.push(line.to_string());
 +            }
 +        } else if start.is_match(line) {
 +            if !replace_start {
 +                new_lines.push(line.to_string());
 +            }
 +            in_old_region = true;
 +            found = true;
 +        } else {
 +            new_lines.push(line.to_string());
 +        }
 +    }
 +
 +    if !found {
 +        // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the
 +        // given text or file. Most likely this is an error on the programmer's side and the Regex
 +        // is incorrect.
 +        eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start);
 +        std::process::exit(1);
 +    }
 +
 +    let mut new_lines = new_lines.join("\n");
 +    if text.ends_with('\n') {
 +        new_lines.push('\n');
 +    }
 +    let changed = new_lines != text;
 +    FileChange { changed, new_lines }
 +}
 +
 +/// 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.");
 +}
 +
 +#[test]
 +fn test_parse_contents() {
 +    let result: Vec<Lint> = parse_contents(
 +        r#"
 +declare_clippy_lint! {
 +    pub PTR_ARG,
 +    style,
 +    "really long \
 +     text"
 +}
 +
 +declare_clippy_lint!{
 +    pub DOC_MARKDOWN,
 +    pedantic,
 +    "single line"
 +}
 +
 +/// some doc comment
 +declare_deprecated_lint! {
 +    pub SHOULD_ASSERT_EQ,
 +    "`assert!()` will be more flexible with RFC 2011"
 +}
 +    "#,
 +        "module_name",
 +    )
 +    .collect();
 +
 +    let expected = vec![
 +        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
 +        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
 +        Lint::new(
 +            "should_assert_eq",
 +            "Deprecated",
 +            "`assert!()` will be more flexible with RFC 2011",
 +            Some("`assert!()` will be more flexible with RFC 2011"),
 +            "module_name",
 +        ),
 +    ];
 +    assert_eq!(expected, result);
 +}
 +
 +#[test]
 +fn test_replace_region() {
 +    let text = "\nabc\n123\n789\ndef\nghi";
 +    let expected = FileChange {
 +        changed: true,
 +        new_lines: "\nabc\nhello world\ndef\nghi".to_string(),
 +    };
 +    let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
 +        vec!["hello world".to_string()]
 +    });
 +    assert_eq!(expected, result);
 +}
 +
 +#[test]
 +fn test_replace_region_with_start() {
 +    let text = "\nabc\n123\n789\ndef\nghi";
 +    let expected = FileChange {
 +        changed: true,
 +        new_lines: "\nhello world\ndef\nghi".to_string(),
 +    };
 +    let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
 +        vec!["hello world".to_string()]
 +    });
 +    assert_eq!(expected, result);
 +}
 +
 +#[test]
 +fn test_replace_region_no_changes() {
 +    let text = "123\n456\n789";
 +    let expected = FileChange {
 +        changed: false,
 +        new_lines: "123\n456\n789".to_string(),
 +    };
 +    let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new);
 +    assert_eq!(expected, result);
 +}
 +
 +#[test]
 +fn test_usable_lints() {
 +    let lints = vec![
 +        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
 +        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"),
 +        Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"),
 +        Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"),
 +    ];
 +    let expected = vec![Lint::new(
 +        "should_assert_eq2",
 +        "Not Deprecated",
 +        "abc",
 +        None,
 +        "module_name",
 +    )];
 +    assert_eq!(expected, Lint::usable_lints(&lints));
 +}
 +
 +#[test]
 +fn test_by_lint_group() {
 +    let lints = vec![
 +        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
 +        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
 +        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
 +    ];
 +    let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
 +    expected.insert(
 +        "group1".to_string(),
 +        vec![
 +            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
 +            Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
 +        ],
 +    );
 +    expected.insert(
 +        "group2".to_string(),
 +        vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
 +    );
 +    assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
 +}
 +
 +#[test]
 +fn test_gen_changelog_lint_list() {
 +    let lints = vec![
 +        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
 +        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
 +    ];
 +    let expected = vec![
 +        format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
 +        format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
 +    ];
 +    assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
 +}
 +
 +#[test]
 +fn test_gen_deprecated() {
 +    let lints = vec![
 +        Lint::new(
 +            "should_assert_eq",
 +            "group1",
 +            "abc",
 +            Some("has been superseded by should_assert_eq2"),
 +            "module_name",
 +        ),
 +        Lint::new(
 +            "another_deprecated",
 +            "group2",
 +            "abc",
 +            Some("will be removed"),
 +            "module_name",
 +        ),
 +    ];
 +    let expected: Vec<String> = vec![
 +        "    store.register_removed(",
 +        "        \"clippy::should_assert_eq\",",
 +        "        \"has been superseded by should_assert_eq2\",",
 +        "    );",
 +        "    store.register_removed(",
 +        "        \"clippy::another_deprecated\",",
 +        "        \"will be removed\",",
 +        "    );",
 +    ]
 +    .into_iter()
 +    .map(String::from)
 +    .collect();
 +    assert_eq!(expected, gen_deprecated(lints.iter()));
 +}
 +
 +#[test]
 +#[should_panic]
 +fn test_gen_deprecated_fail() {
 +    let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")];
 +    let _ = gen_deprecated(lints.iter());
 +}
 +
 +#[test]
 +fn test_gen_modules_list() {
 +    let lints = vec![
 +        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
 +        Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"),
 +    ];
 +    let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()];
 +    assert_eq!(expected, gen_modules_list(lints.iter()));
 +}
 +
 +#[test]
 +fn test_gen_lint_group_list() {
 +    let lints = vec![
 +        Lint::new("abc", "group1", "abc", None, "module_name"),
 +        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
 +        Lint::new("internal", "internal_style", "abc", None, "module_name"),
 +    ];
 +    let expected = vec![
 +        "        LintId::of(&module_name::ABC),".to_string(),
 +        "        LintId::of(&module_name::INTERNAL),".to_string(),
 +        "        LintId::of(&module_name::SHOULD_ASSERT_EQ),".to_string(),
 +    ];
 +    assert_eq!(expected, gen_lint_group_list(lints.iter()));
 +}
index a8a6a2cb1bd6fbd4fdfa27a707679450d7838bc5,0000000000000000000000000000000000000000..a3c329b578b2050d411c9ee0d010354a5c176699
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,101 @@@
 +use std::fs;
 +use std::fs::File;
 +use std::io::prelude::*;
 +use std::path::{Path, PathBuf};
 +
 +// This module takes an absolute path to a rustc repo and alters the dependencies to point towards
 +// the respective rustc subcrates instead of using extern crate xyz.
 +// This allows rust analyzer to analyze rustc internals and show proper information inside clippy
 +// code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details
 +
++/// # Panics
++///
++/// Panics if `rustc_path` does not lead to a rustc repo or the files could not be read
 +pub fn run(rustc_path: Option<&str>) {
 +    // we can unwrap here because the arg is required by clap
 +    let rustc_path = PathBuf::from(rustc_path.unwrap());
 +    assert!(rustc_path.is_dir(), "path is not a directory");
 +    let rustc_source_basedir = rustc_path.join("compiler");
 +    assert!(
 +        rustc_source_basedir.is_dir(),
 +        "are you sure the path leads to a rustc repo?"
 +    );
 +
 +    let clippy_root_manifest = fs::read_to_string("Cargo.toml").expect("failed to read ./Cargo.toml");
 +    let clippy_root_lib_rs = fs::read_to_string("src/driver.rs").expect("failed to read ./src/driver.rs");
 +    inject_deps_into_manifest(
 +        &rustc_source_basedir,
 +        "Cargo.toml",
 +        &clippy_root_manifest,
 +        &clippy_root_lib_rs,
 +    )
 +    .expect("Failed to inject deps into ./Cargo.toml");
 +
 +    let clippy_lints_manifest =
 +        fs::read_to_string("clippy_lints/Cargo.toml").expect("failed to read ./clippy_lints/Cargo.toml");
 +    let clippy_lints_lib_rs =
 +        fs::read_to_string("clippy_lints/src/lib.rs").expect("failed to read ./clippy_lints/src/lib.rs");
 +    inject_deps_into_manifest(
 +        &rustc_source_basedir,
 +        "clippy_lints/Cargo.toml",
 +        &clippy_lints_manifest,
 +        &clippy_lints_lib_rs,
 +    )
 +    .expect("Failed to inject deps into ./clippy_lints/Cargo.toml");
 +}
 +
 +fn inject_deps_into_manifest(
 +    rustc_source_dir: &Path,
 +    manifest_path: &str,
 +    cargo_toml: &str,
 +    lib_rs: &str,
 +) -> std::io::Result<()> {
 +    // do not inject deps if we have aleady done so
 +    if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") {
 +        eprintln!(
 +            "cargo dev ra_setup: warning: deps already found inside {}, doing nothing.",
 +            manifest_path
 +        );
 +        return Ok(());
 +    }
 +
 +    let extern_crates = lib_rs
 +        .lines()
 +        // get the deps
 +        .filter(|line| line.starts_with("extern crate"))
 +        // we have something like "extern crate foo;", we only care about the "foo"
 +        //              ↓          ↓
 +        // extern crate rustc_middle;
 +        .map(|s| &s[13..(s.len() - 1)]);
 +
 +    let new_deps = extern_crates.map(|dep| {
 +        // format the dependencies that are going to be put inside the Cargo.toml
 +        format!(
 +            "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
 +            dep = dep,
 +            source_path = rustc_source_dir.display()
 +        )
 +    });
 +
 +    // format a new [dependencies]-block with the new deps we need to inject
 +    let mut all_deps = String::from("[target.'cfg(NOT_A_PLATFORM)'.dependencies]\n");
 +    new_deps.for_each(|dep_line| {
 +        all_deps.push_str(&dep_line);
 +    });
 +    all_deps.push_str("\n[dependencies]\n");
 +
 +    // replace "[dependencies]" with
 +    // [dependencies]
 +    // dep1 = { path = ... }
 +    // dep2 = { path = ... }
 +    // etc
 +    let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1);
 +
 +    // println!("{}", new_manifest);
 +    let mut file = File::create(manifest_path)?;
 +    file.write_all(new_manifest.as_bytes())?;
 +
 +    println!("Dependency paths injected: {}", manifest_path);
 +
 +    Ok(())
 +}
index a46c0e4d3f0a1525eb39ee56bee441eec6e710fd,0000000000000000000000000000000000000000..faa94859601e3a3e010af89a223956caba8b520a
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,67 @@@
 +use std::ffi::{OsStr, OsString};
 +use std::path::Path;
 +use std::process::Command;
 +use std::thread;
 +use std::time::{Duration, SystemTime};
 +
++/// # Panics
++///
++/// Panics if the python commands could not be spawned
 +pub fn run(port: u16, lint: Option<&str>) -> ! {
 +    let mut url = Some(match lint {
 +        None => format!("http://localhost:{}", port),
 +        Some(lint) => format!("http://localhost:{}/#{}", port, lint),
 +    });
 +
 +    loop {
 +        if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
 +            Command::new("python3")
 +                .arg("util/export.py")
 +                .spawn()
 +                .unwrap()
 +                .wait()
 +                .unwrap();
 +        }
 +        if let Some(url) = url.take() {
 +            thread::spawn(move || {
 +                Command::new("python3")
 +                    .arg("-m")
 +                    .arg("http.server")
 +                    .arg(port.to_string())
 +                    .current_dir("util/gh-pages")
 +                    .spawn()
 +                    .unwrap();
 +                // Give some time for python to start
 +                thread::sleep(Duration::from_millis(500));
 +                // Launch browser after first export.py has completed and http.server is up
 +                let _ = opener::open(url);
 +            });
 +        }
 +        thread::sleep(Duration::from_millis(1000));
 +    }
 +}
 +
 +fn mtime(path: impl AsRef<Path>) -> SystemTime {
 +    let path = path.as_ref();
 +    if path.is_dir() {
 +        path.read_dir()
 +            .into_iter()
 +            .flatten()
 +            .flatten()
 +            .map(|entry| mtime(&entry.path()))
 +            .max()
 +            .unwrap_or(SystemTime::UNIX_EPOCH)
 +    } else {
 +        path.metadata()
 +            .and_then(|metadata| metadata.modified())
 +            .unwrap_or(SystemTime::UNIX_EPOCH)
 +    }
 +}
 +
 +#[allow(clippy::missing_errors_doc)]
 +pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
 +    match arg.to_string_lossy().parse::<u16>() {
 +        Ok(_port) => Ok(()),
 +        Err(err) => Err(OsString::from(err.to_string())),
 +    }
 +}
index fa0289c977c7253ab2ed3bfa9dd579fed7b261d2,0000000000000000000000000000000000000000..75e71eb1e4ce23158998b6bec356cf0e1f27780e
mode 100644,000000..100644
--- /dev/null
@@@ -1,611 -1,0 +1,726 @@@
- use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
++use crate::utils::{
++    implements_trait, is_entrypoint_fn, is_type_diagnostic_item, match_panic_def_id, method_chain_args, return_ty,
++    span_lint, span_lint_and_note,
++};
 +use if_chain::if_chain;
 +use itertools::Itertools;
 +use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind};
 +use rustc_ast::token::CommentKind;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_data_structures::sync::Lrc;
 +use rustc_errors::emitter::EmitterWriter;
 +use rustc_errors::Handler;
 +use rustc_hir as hir;
++use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
++use rustc_hir::{Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
++use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_parse::maybe_new_parser_from_source_str;
 +use rustc_parse::parser::ForceCollect;
 +use rustc_session::parse::ParseSess;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::edition::Edition;
 +use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
 +use rustc_span::{sym, FileName, Pos};
 +use std::io;
 +use std::ops::Range;
 +use 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.
 +    ///
 +    /// In addition, when writing documentation comments, including `[]` brackets
 +    /// inside a link text would trip the parser. Therfore, documenting link with
 +    /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
 +    /// would fail.
 +    ///
 +    /// **Examples:**
 +    /// ```rust
 +    /// /// Do something with the foo_bar parameter. See also
 +    /// /// that::other::module::foo.
 +    /// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
 +    /// fn doit(foo_bar: usize) {}
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// // Link text with `[]` brackets should be written as following:
 +    /// /// Consume the array and return the inner
 +    /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
 +    /// /// [SmallVec]: SmallVec
 +    /// fn main() {}
 +    /// ```
 +    pub DOC_MARKDOWN,
 +    pedantic,
 +    "presence of `_`, `::` or camel-case outside backticks in documentation"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for the doc comments of publicly visible
 +    /// unsafe functions and warns if there is no `# Safety` section.
 +    ///
 +    /// **Why is this bad?** Unsafe functions should document their safety
 +    /// preconditions, so that users can be sure they are using them safely.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// This function should really be documented
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    ///
 +    /// At least write a line about safety:
 +    ///
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// # Safety
 +    /// ///
 +    /// /// This function should not be called before the horsemen are ready.
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_SAFETY_DOC,
 +    style,
 +    "`pub unsafe fn` without `# Safety` docs"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks the doc comments of publicly visible functions that
 +    /// return a `Result` type and warns if there is no `# Errors` section.
 +    ///
 +    /// **Why is this bad?** Documenting the type of errors that can be returned from a
 +    /// function can help callers write code to handle the errors appropriately.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    ///
 +    /// Since the following function returns a `Result` it has an `# Errors` section in
 +    /// its doc comment:
 +    ///
 +    /// ```rust
 +    ///# use std::io;
 +    /// /// # Errors
 +    /// ///
 +    /// /// Will return `Err` if `filename` does not exist or the user does not have
 +    /// /// permission to read it.
 +    /// pub fn read(filename: String) -> io::Result<String> {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_ERRORS_DOC,
 +    pedantic,
 +    "`pub fn` returns `Result` without `# Errors` in doc comment"
 +}
 +
++declare_clippy_lint! {
++    /// **What it does:** Checks 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.
++    ///
++    /// **Known problems:** None.
++    ///
++    /// **Examples:**
++    ///
++    /// Since the following function may panic it has a `# Panics` section in
++    /// its doc comment:
++    ///
++    /// ```rust
++    /// /// # Panics
++    /// ///
++    /// /// Will panic if y is 0
++    /// pub fn divide_by(x: i32, y: i32) -> i32 {
++    ///     if y == 0 {
++    ///         panic!("Cannot divide by 0")
++    ///     } else {
++    ///         x / y
++    ///     }
++    /// }
++    /// ```
++    pub MISSING_PANICS_DOC,
++    pedantic,
++    "`pub fn` may panic without `# Panics` in doc comment"
++}
++
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `fn main() { .. }` in doctests
 +    ///
 +    /// **Why is this bad?** The test can be shorter (and likely more readable)
 +    /// if the `fn main()` is left implicit.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Examples:**
 +    /// ``````rust
 +    /// /// An example of a doctest with a `main()` function
 +    /// ///
 +    /// /// # Examples
 +    /// ///
 +    /// /// ```
 +    /// /// fn main() {
 +    /// ///     // this needs not be in an `fn`
 +    /// /// }
 +    /// /// ```
 +    /// fn needless_main() {
 +    ///     unimplemented!();
 +    /// }
 +    /// ``````
 +    pub NEEDLESS_DOCTEST_MAIN,
 +    style,
 +    "presence of `fn main() {` in code examples"
 +}
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Clone)]
 +pub struct DocMarkdown {
 +    valid_idents: FxHashSet<String>,
 +    in_trait_impl: bool,
 +}
 +
 +impl DocMarkdown {
 +    pub fn new(valid_idents: FxHashSet<String>) -> Self {
 +        Self {
 +            valid_idents,
 +            in_trait_impl: false,
 +        }
 +    }
 +}
 +
- impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, NEEDLESS_DOCTEST_MAIN]);
++impl_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>, krate: &'tcx hir::Crate<'_>) {
 +        check_attrs(cx, &self.valid_idents, &krate.item.attrs);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        match item.kind {
 +            hir::ItemKind::Fn(ref sig, _, body_id) => {
 +                if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id())
 +                    || in_external_macro(cx.tcx.sess, item.span))
 +                {
-                     lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
++                    let body = cx.tcx.hir().body(body_id);
++                    let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id);
++                    let mut fpu = FindPanicUnwrap {
++                        cx,
++                        typeck_results: cx.tcx.typeck(impl_item_def_id),
++                        panic_span: None,
++                    };
++                    fpu.visit_expr(&body.value);
++                    lint_for_missing_headers(cx, item.hir_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();
 +            },
 +            _ => {},
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        if let hir::ItemKind::Impl { .. } = item.kind {
 +            self.in_trait_impl = false;
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
 +            if !in_external_macro(cx.tcx.sess, item.span) {
-                 lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None);
++                lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None, None);
 +            }
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
 +        let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
 +        if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +        if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
-             lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
++            let body = cx.tcx.hir().body(body_id);
++            let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id);
++            let mut fpu = FindPanicUnwrap {
++                cx,
++                typeck_results: cx.tcx.typeck(impl_item_def_id),
++                panic_span: None,
++            };
++            fpu.visit_expr(&body.value);
++            lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
 +        }
 +    }
 +}
 +
 +fn lint_for_missing_headers<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    hir_id: hir::HirId,
 +    span: impl Into<MultiSpan> + Copy,
 +    sig: &hir::FnSig<'_>,
 +    headers: DocHeaders,
 +    body_id: Option<hir::BodyId>,
++    panic_span: Option<Span>,
 +) {
 +    if !cx.access_levels.is_exported(hir_id) {
 +        return; // Private functions do not require doc comments
 +    }
 +    if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
 +        span_lint(
 +            cx,
 +            MISSING_SAFETY_DOC,
 +            span,
 +            "unsafe function's docs miss `# Safety` section",
 +        );
 +    }
++    if !headers.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 {
 +        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
 +            span_lint(
 +                cx,
 +                MISSING_ERRORS_DOC,
 +                span,
 +                "docs for function returning `Result` missing `# Errors` section",
 +            );
 +        } else {
 +            if_chain! {
 +                if let Some(body_id) = body_id;
 +                if let Some(future) = cx.tcx.lang_items().future_trait();
 +                let def_id = cx.tcx.hir().body_owner_def_id(body_id);
 +                let mir = cx.tcx.optimized_mir(def_id.to_def_id());
 +                let ret_ty = mir.return_ty();
 +                if implements_trait(cx, ret_ty, future, &[]);
 +                if let ty::Opaque(_, subs) = ret_ty.kind();
 +                if let Some(gen) = subs.types().next();
 +                if let ty::Generator(_, subs, _) = gen.kind();
 +                if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::result_type);
 +                then {
 +                    span_lint(
 +                        cx,
 +                        MISSING_ERRORS_DOC,
 +                        span,
 +                        "docs for function returning `Result` missing `# Errors` section",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Cleanup documentation decoration.
 +///
 +/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
 +/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
 +/// need to keep track of
 +/// the spans but this function is inspired from the later.
 +#[allow(clippy::cast_possible_truncation)]
 +#[must_use]
 +pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
 +    // one-line comments lose their prefix
 +    if comment_kind == CommentKind::Line {
 +        let mut doc = doc.to_owned();
 +        doc.push('\n');
 +        let len = doc.len();
 +        // +3 skips the opening delimiter
 +        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
 +    }
 +
 +    let mut sizes = vec![];
 +    let mut contains_initial_stars = false;
 +    for line in doc.lines() {
 +        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
 +        debug_assert_eq!(offset as u32 as usize, offset);
 +        contains_initial_stars |= line.trim_start().starts_with('*');
 +        // +1 adds the newline, +3 skips the opening delimiter
 +        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
 +    }
 +    if !contains_initial_stars {
 +        return (doc.to_string(), sizes);
 +    }
 +    // remove the initial '*'s if any
 +    let mut no_stars = String::with_capacity(doc.len());
 +    for line in doc.lines() {
 +        let mut chars = line.chars();
 +        while let Some(c) = chars.next() {
 +            if c.is_whitespace() {
 +                no_stars.push(c);
 +            } else {
 +                no_stars.push(if c == '*' { ' ' } else { c });
 +                break;
 +            }
 +        }
 +        no_stars.push_str(chars.as_str());
 +        no_stars.push('\n');
 +    }
 +
 +    (no_stars, sizes)
 +}
 +
 +#[derive(Copy, Clone)]
 +struct DocHeaders {
 +    safety: bool,
 +    errors: bool,
++    panics: bool,
 +}
 +
 +fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
 +    let mut doc = String::new();
 +    let mut spans = vec![];
 +
 +    for attr in attrs {
 +        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
 +            let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
 +            spans.extend_from_slice(&current_spans);
 +            doc.push_str(&comment);
 +        } else if attr.has_name(sym::doc) {
 +            // ignore mix of sugared and non-sugared doc
 +            // don't trigger the safety or errors check
 +            return DocHeaders {
 +                safety: true,
 +                errors: true,
++                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 parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
 +    // Iterate over all `Events` and combine consecutive events into one
 +    let events = parser.coalesce(|previous, current| {
 +        use pulldown_cmark::Event::Text;
 +
 +        let previous_range = previous.1;
 +        let current_range = current.1;
 +
 +        match (previous.0, current.0) {
 +            (Text(previous), Text(current)) => {
 +                let mut previous = previous.to_string();
 +                previous.push_str(&current);
 +                Ok((Text(previous.into()), previous_range))
 +            },
 +            (previous, current) => Err(((previous, previous_range), (current, current_range))),
 +        }
 +    });
 +    check_doc(cx, valid_idents, events, &spans)
 +}
 +
 +const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
 +
 +fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
 +    cx: &LateContext<'_>,
 +    valid_idents: &FxHashSet<String>,
 +    events: Events,
 +    spans: &[(usize, Span)],
 +) -> DocHeaders {
 +    // true if a safety header was found
 +    use pulldown_cmark::CodeBlockKind;
 +    use pulldown_cmark::Event::{
 +        Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 +    };
 +    use pulldown_cmark::Tag::{CodeBlock, Heading, Link};
 +
 +    let mut headers = DocHeaders {
 +        safety: false,
 +        errors: false,
++        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;
 +    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(_)) => in_heading = true,
 +            End(Heading(_)) => in_heading = false,
 +            Start(_tag) | End(_tag) => (), // We don't care about other tags
 +            Html(_html) => (),             // HTML is weird, just ignore it
 +            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
 +            FootnoteReference(text) | Text(text) => {
 +                if Some(&text) == in_link.as_ref() {
 +                    // Probably a link of the form `<http://example.com>`
 +                    // Which are represented as a link to "http://example.com" with
 +                    // text "http://example.com" by pulldown-cmark
 +                    continue;
 +                }
 +                headers.safety |= in_heading && text.trim() == "Safety";
 +                headers.errors |= in_heading && text.trim() == "Errors";
++                headers.panics |= in_heading && text.trim() == "Panics";
 +                let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) {
 +                    Ok(o) => o,
 +                    Err(e) => e - 1,
 +                };
 +                let (begin, span) = spans[index];
 +                if in_code {
 +                    if is_rust {
 +                        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));
 +
 +                    check_text(cx, valid_idents, &text, span);
 +                }
 +            },
 +        }
 +    }
 +    headers
 +}
 +
 +fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
 +    fn has_needless_main(code: &str, edition: Edition) -> bool {
 +        rustc_driver::catch_fatal_errors(|| {
 +            rustc_span::with_session_globals(edition, || {
 +                let filename = FileName::anon_source_code(code);
 +
 +                let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
 +                let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
 +                let handler = Handler::with_emitter(false, None, box emitter);
 +                let sess = ParseSess::with_span_handler(handler, sm);
 +
 +                let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code.into()) {
 +                    Ok(p) => p,
 +                    Err(errs) => {
 +                        for mut err in errs {
 +                            err.cancel();
 +                        }
 +                        return false;
 +                    },
 +                };
 +
 +                let mut relevant_main_found = false;
 +                loop {
 +                    match parser.parse_item(ForceCollect::No) {
 +                        Ok(Some(item)) => match &item.kind {
 +                            // Tests with one of these items are ignored
 +                            ItemKind::Static(..)
 +                            | ItemKind::Const(..)
 +                            | ItemKind::ExternCrate(..)
 +                            | ItemKind::ForeignMod(..) => return false,
 +                            // We found a main function ...
 +                            ItemKind::Fn(box FnKind(_, sig, _, Some(block)))
 +                                if item.ident.name == sym::main =>
 +                            {
 +                                let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
 +                                let returns_nothing = match &sig.decl.output {
 +                                    FnRetTy::Default(..) => true,
 +                                    FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
 +                                    _ => false,
 +                                };
 +
 +                                if returns_nothing && !is_async && !block.stmts.is_empty() {
 +                                    // This main function should be linted, but only if there are no other functions
 +                                    relevant_main_found = true;
 +                                } else {
 +                                    // This main function should not be linted, we're done
 +                                    return false;
 +                                }
 +                            },
 +                            // Another function was found; this case is ignored too
 +                            ItemKind::Fn(..) => return false,
 +                            _ => {},
 +                        },
 +                        Ok(None) => break,
 +                        Err(mut e) => {
 +                            e.cancel();
 +                            return false;
 +                        },
 +                    }
 +                }
 +
 +                relevant_main_found
 +            })
 +        })
 +        .ok()
 +        .unwrap_or_default()
 +    }
 +
 +    if has_needless_main(text, edition) {
 +        span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
 +    }
 +}
 +
 +fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
 +    for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
 +        // Trim punctuation as in `some comment (see foo::bar).`
 +        //                                                   ^^
 +        // Or even as in `_foo bar_` which is emphasized.
 +        let word = word.trim_matches(|c: char| !c.is_alphanumeric());
 +
 +        if valid_idents.contains(word) {
 +            continue;
 +        }
 +
 +        // Adjust for the current word
 +        let offset = word.as_ptr() as usize - text.as_ptr() as usize;
 +        let span = Span::new(
 +            span.lo() + BytePos::from_usize(offset),
 +            span.lo() + BytePos::from_usize(offset + word.len()),
 +            span.ctxt(),
 +        );
 +
 +        check_word(cx, word, span);
 +    }
 +}
 +
 +fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
 +    /// Checks if a string is camel-case, i.e., contains at least two uppercase
 +    /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
 +    /// Plurals are also excluded (`IDs` is ok).
 +    fn is_camel_case(s: &str) -> bool {
 +        if s.starts_with(|c: char| c.is_digit(10)) {
 +            return false;
 +        }
 +
 +        let s = s.strip_suffix('s').unwrap_or(s);
 +
 +        s.chars().all(char::is_alphanumeric)
 +            && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
 +            && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
 +    }
 +
 +    fn has_underscore(s: &str) -> bool {
 +        s != "_" && !s.contains("\\_") && s.contains('_')
 +    }
 +
 +    fn has_hyphen(s: &str) -> bool {
 +        s != "-" && s.contains('-')
 +    }
 +
 +    if let Ok(url) = Url::parse(word) {
 +        // try to get around the fact that `foo::bar` parses as a valid URL
 +        if !url.cannot_be_a_base() {
 +            span_lint(
 +                cx,
 +                DOC_MARKDOWN,
 +                span,
 +                "you should put bare URLs between `<`/`>` or make a proper Markdown link",
 +            );
 +
 +            return;
 +        }
 +    }
 +
 +    // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
 +    if has_underscore(word) && has_hyphen(word) {
 +        return;
 +    }
 +
 +    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
 +        span_lint(
 +            cx,
 +            DOC_MARKDOWN,
 +            span,
 +            &format!("you should put `{}` between ticks in the documentation", word),
 +        );
 +    }
 +}
++
++struct FindPanicUnwrap<'a, 'tcx> {
++    cx: &'a LateContext<'tcx>,
++    panic_span: Option<Span>,
++    typeck_results: &'tcx ty::TypeckResults<'tcx>,
++}
++
++impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
++    type Map = Map<'tcx>;
++
++    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
++        if self.panic_span.is_some() {
++            return;
++        }
++
++        // check for `begin_panic`
++        if_chain! {
++            if let ExprKind::Call(ref func_expr, _) = expr.kind;
++            if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
++            if let Some(path_def_id) = path.res.opt_def_id();
++            if match_panic_def_id(self.cx, path_def_id);
++            then {
++                self.panic_span = Some(expr.span);
++            }
++        }
++
++        // check for `unwrap`
++        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
++            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
++            if is_type_diagnostic_item(self.cx, reciever_ty, sym::option_type)
++                || is_type_diagnostic_item(self.cx, reciever_ty, sym::result_type)
++            {
++                self.panic_span = Some(expr.span);
++            }
++        }
++
++        // and check sub-expressions
++        intravisit::walk_expr(self, expr);
++    }
++
++    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
++        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
++    }
++}
index fecde8e2743483d16b51c4a6295192ff1a8bdc6f,0000000000000000000000000000000000000000..6f22f65deac80ec183d003c4b7ac0ebeb1f581df
mode 100644,000000..100644
--- /dev/null
@@@ -1,176 -1,0 +1,178 @@@
-             }
-             ItemKind::Impl(box ImplKind { of_trait: None, items, .. })
 +use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help};
 +use rustc_ast::ast::{
 +    AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::Span;
 +
 +use std::convert::TryInto;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for excessive
 +    /// use of bools in structs.
 +    ///
 +    /// **Why is this bad?** Excessive bools in a struct
 +    /// is often a sign that it's used as a state machine,
 +    /// which is much better implemented as an enum.
 +    /// If it's not the case, excessive bools usually benefit
 +    /// from refactoring into two-variant enums for better
 +    /// readability and API.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust
 +    /// struct S {
 +    ///     is_pending: bool,
 +    ///     is_processing: bool,
 +    ///     is_finished: bool,
 +    /// }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust
 +    /// enum S {
 +    ///     Pending,
 +    ///     Processing,
 +    ///     Finished,
 +    /// }
 +    /// ```
 +    pub STRUCT_EXCESSIVE_BOOLS,
 +    pedantic,
 +    "using too many bools in a struct"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for excessive use of
 +    /// bools in function definitions.
 +    ///
 +    /// **Why is this bad?** Calls to such functions
 +    /// are confusing and error prone, because it's
 +    /// hard to remember argument order and you have
 +    /// no type system support to back you up. Using
 +    /// two-variant enums instead of bools often makes
 +    /// API easier to use.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// fn f(is_round: bool, is_hot: bool) { ... }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// enum Shape {
 +    ///     Round,
 +    ///     Spiky,
 +    /// }
 +    ///
 +    /// enum Temperature {
 +    ///     Hot,
 +    ///     IceCold,
 +    /// }
 +    ///
 +    /// fn f(shape: Shape, temperature: Temperature) { ... }
 +    /// ```
 +    pub FN_PARAMS_EXCESSIVE_BOOLS,
 +    pedantic,
 +    "using too many bools in function parameters"
 +}
 +
 +pub struct ExcessiveBools {
 +    max_struct_bools: u64,
 +    max_fn_params_bools: u64,
 +}
 +
 +impl ExcessiveBools {
 +    #[must_use]
 +    pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
 +        Self {
 +            max_struct_bools,
 +            max_fn_params_bools,
 +        }
 +    }
 +
 +    fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) {
 +        match fn_sig.header.ext {
 +            Extern::Implicit | Extern::Explicit(_) => return,
 +            Extern::None => (),
 +        }
 +
 +        let fn_sig_bools = fn_sig
 +            .decl
 +            .inputs
 +            .iter()
 +            .filter(|param| is_bool_ty(&param.ty))
 +            .count()
 +            .try_into()
 +            .unwrap();
 +        if self.max_fn_params_bools < fn_sig_bools {
 +            span_lint_and_help(
 +                cx,
 +                FN_PARAMS_EXCESSIVE_BOOLS,
 +                span,
 +                &format!("more than {} bools in function parameters", self.max_fn_params_bools),
 +                None,
 +                "consider refactoring bools into two-variant enums",
 +            );
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
 +
 +fn is_bool_ty(ty: &Ty) -> bool {
 +    if let TyKind::Path(None, path) = &ty.kind {
 +        return match_path_ast(path, &["bool"]);
 +    }
 +    false
 +}
 +
 +impl EarlyLintPass for ExcessiveBools {
 +    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 +        if in_macro(item.span) {
 +            return;
 +        }
 +        match &item.kind {
 +            ItemKind::Struct(variant_data, _) => {
 +                if attr_by_name(&item.attrs, "repr").is_some() {
 +                    return;
 +                }
 +
 +                let struct_bools = variant_data
 +                    .fields()
 +                    .iter()
 +                    .filter(|field| is_bool_ty(&field.ty))
 +                    .count()
 +                    .try_into()
 +                    .unwrap();
 +                if self.max_struct_bools < struct_bools {
 +                    span_lint_and_help(
 +                        cx,
 +                        STRUCT_EXCESSIVE_BOOLS,
 +                        item.span,
 +                        &format!("more than {} bools in a struct", self.max_struct_bools),
 +                        None,
 +                        "consider using a state machine or refactoring bools into two-variant enums",
 +                    );
 +                }
-             }
++            },
++            ItemKind::Impl(box ImplKind {
++                of_trait: None, items, ..
++            })
 +            | ItemKind::Trait(box TraitKind(.., items)) => {
 +                for item in items {
 +                    if let AssocItemKind::Fn(box FnKind(_, fn_sig, _, _)) = &item.kind {
 +                        self.check_fn_sig(cx, fn_sig, item.span);
 +                    }
 +                }
++            },
 +            ItemKind::Fn(box FnKind(_, fn_sig, _, _)) => self.check_fn_sig(cx, fn_sig, item.span),
 +            _ => (),
 +        }
 +    }
 +}
index 32b1299efce91d1fe44fdbac532f1ecf52dbd3c0,0000000000000000000000000000000000000000..e3988d0038c23b8f2e187afad6d3836c62a049fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,106 @@@
-                 let (lint, msg) = if let ItemKind::Enum(..) = item.kind {
-                     (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
-                 } else {
 +use crate::utils::{indent_of, span_lint_and_then};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
 +    ///
 +    /// **Why is this bad?** Exhaustive enums are typically fine, but a project which does
 +    /// not wish to make a stability commitment around exported enums may wish to
 +    /// disable them by default.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// enum Foo {
 +    ///     Bar,
 +    ///     Baz
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// #[non_exhaustive]
 +    /// enum Foo {
 +    ///     Bar,
 +    ///     Baz
 +    /// }
 +    /// ```
 +    pub EXHAUSTIVE_ENUMS,
 +    restriction,
 +    "detects exported enums that have not been marked #[non_exhaustive]"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
 +    ///
 +    /// **Why is this bad?** Exhaustive structs are typically fine, but a project which does
 +    /// not wish to make a stability commitment around exported structs may wish to
 +    /// disable them by default.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// struct Foo {
 +    ///     bar: u8,
 +    ///     baz: String,
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// #[non_exhaustive]
 +    /// struct Foo {
 +    ///     bar: u8,
 +    ///     baz: String,
 +    /// }
 +    /// ```
 +    pub EXHAUSTIVE_STRUCTS,
 +    restriction,
 +    "detects exported structs that have not been marked #[non_exhaustive]"
 +}
 +
 +declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
 +
 +impl LateLintPass<'_> for ExhaustiveItems {
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        if_chain! {
 +            if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
 +            if cx.access_levels.is_exported(item.hir_id);
 +            if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
 +            then {
++                let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
++                    if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
++                        // skip structs with private fields
++                        return;
++                    }
 +                    (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
++                } else {
++                    (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
 +                };
 +                let suggestion_span = item.span.shrink_to_lo();
 +                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
 +                span_lint_and_then(
 +                    cx,
 +                    lint,
 +                    item.span,
 +                    msg,
 +                    |diag| {
 +                        let sugg = format!("#[non_exhaustive]\n{}", indent);
 +                        diag.span_suggestion(suggestion_span,
 +                                             "try adding #[non_exhaustive]",
 +                                             sugg,
 +                                             Applicability::MaybeIncorrect);
 +                    }
 +                );
 +
 +            }
 +        }
 +    }
 +}
index 54007c29c6c5efbb8af522a3d18932503b372496,0000000000000000000000000000000000000000..5a40c00bd673a6223ed7a3e2508a0f87fdbe591b
mode 100644,000000..100644
--- /dev/null
@@@ -1,2092 -1,0 +1,2094 @@@
 +// error-pattern:cargo-clippy
 +
 +#![feature(bindings_after_at)]
 +#![feature(box_patterns)]
 +#![feature(box_syntax)]
 +#![feature(concat_idents)]
 +#![feature(crate_visibility_modifier)]
 +#![feature(drain_filter)]
 +#![feature(in_band_lifetimes)]
 +#![feature(once_cell)]
 +#![feature(or_patterns)]
 +#![feature(rustc_private)]
 +#![feature(stmt_expr_attributes)]
 +#![feature(control_flow_enum)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![deny(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_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;
 +extern crate rustc_parse;
 +extern crate rustc_parse_format;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +use crate::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`, `complexity` and `perf` are enabled by default.
 +/// As said in the README.md of this repository, if the lint level mapping changes, please update
 +/// README.md.
 +///
 +/// # Example
 +///
 +/// ```
 +/// #![feature(rustc_private)]
 +/// extern crate rustc_session;
 +/// use rustc_session::declare_tool_lint;
 +/// use clippy_lints::declare_clippy_lint;
 +///
 +/// declare_clippy_lint! {
 +///     /// **What it does:** Checks for ... (describe what the lint matches).
 +///     ///
 +///     /// **Why is this bad?** Supply the reason for linting the code.
 +///     ///
 +///     /// **Known problems:** None. (Or describe where it could go wrong.)
 +///     ///
 +///     /// **Example:**
 +///     ///
 +///     /// ```rust
 +///     /// // Bad
 +///     /// Insert a short example of code that triggers the lint
 +///     ///
 +///     /// // Good
 +///     /// Insert a short example of improved code that doesn't trigger the lint
 +///     /// ```
 +///     pub LINT_NAME,
 +///     pedantic,
 +///     "description"
 +/// }
 +/// ```
 +/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +#[macro_export]
 +macro_rules! declare_clippy_lint {
 +    { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +}
 +
 +mod consts;
 +#[macro_use]
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod async_yields_async;
 +mod atomic_ordering;
 +mod attrs;
 +mod await_holding_invalid;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod booleans;
 +mod bytecount;
 +mod cargo_common_metadata;
 +mod case_sensitive_file_extension_comparisons;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod collapsible_match;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod dereference;
 +mod derive;
 +mod disallowed_method;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duration_subsec;
 +mod else_if_without_else;
 +mod empty_enum;
 +mod entry;
 +mod enum_clike;
 +mod enum_variants;
 +mod eq_op;
 +mod 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 formatting;
 +mod from_over_into;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_let_some_result;
 +mod if_not_else;
 +mod implicit_return;
 +mod implicit_saturating_sub;
 +mod indexing_slicing;
 +mod infinite_iter;
 +mod inherent_impl;
 +mod inherent_to_string;
 +mod inline_fn_without_body;
 +mod int_plus_one;
 +mod integer_division;
 +mod items_after_statements;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_stack_arrays;
 +mod len_zero;
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
 +mod manual_async_fn;
 +mod manual_non_exhaustive;
 +mod manual_ok_or;
 +mod manual_strip;
 +mod manual_unwrap_or;
 +mod map_clone;
 +mod map_err_ignore;
 +mod map_identity;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod matches;
 +mod mem_discriminant;
 +mod mem_forget;
 +mod mem_replace;
 +mod methods;
 +mod minmax;
 +mod misc;
 +mod misc_early;
 +mod missing_const_for_fn;
 +mod missing_doc;
 +mod missing_inline;
 +mod modulo_arithmetic;
 +mod multiple_crate_versions;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_mutex_lock;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bool;
 +mod needless_borrow;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_pass_by_value;
 +mod needless_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 open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod pass_by_ref_or_value;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_eq;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_else;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_slicing;
 +mod redundant_static_lifetimes;
 +mod ref_option_ref;
 +mod reference;
 +mod regex;
 +mod repeat_once;
 +mod returns;
 +mod self_assignment;
 +mod serde_api;
 +mod shadow;
 +mod single_component_path_imports;
 +mod size_of_in_element_count;
 +mod slow_vector_initialization;
 +mod stable_sort_primitive;
 +mod strings;
 +mod suspicious_operation_groupings;
 +mod suspicious_trait_impl;
 +mod swap;
 +mod tabs_in_doc_comments;
 +mod temporary_assignment;
 +mod to_digit_is_some;
 +mod to_string_in_display;
 +mod trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod try_err;
 +mod types;
 +mod undropped_manually_drops;
 +mod unicode;
 +mod unit_return_expecting_ord;
 +mod unnamed_address;
 +mod unnecessary_sort_by;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_io_amount;
 +mod unused_self;
 +mod unused_unit;
 +mod unwrap;
 +mod unwrap_in_result;
 +mod upper_case_acronyms;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_init_then_push;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_dependencies;
 +mod wildcard_imports;
 +mod write;
 +mod zero_div_zero;
 +mod zero_sized_map_values;
 +// end lints modules, do not remove this comment, it’s used in `update_lints`
 +
 +pub use crate::utils::conf::Conf;
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_pre_expansion_pass(|| box write::Write::default());
 +    store.register_pre_expansion_pass(|| box attrs::EarlyAttributes);
 +    store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro);
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(args: &[rustc_ast::NestedMetaItem], sess: &Session) -> Conf {
 +    use std::path::Path;
 +    match utils::conf::file_from_args(args) {
 +        Ok(file_name) => {
 +            // if the user specified a file, it must exist, otherwise default to `clippy.toml` but
 +            // do not require the file to exist
 +            let file_name = match file_name {
 +                Some(file_name) => file_name,
 +                None => match utils::conf::lookup_conf_file() {
 +                    Ok(Some(path)) => path,
 +                    Ok(None) => return Conf::default(),
 +                    Err(error) => {
 +                        sess.struct_err(&format!("error finding Clippy's configuration file: {}", error))
 +                            .emit();
 +                        return Conf::default();
 +                    },
 +                },
 +            };
 +
 +            let file_name = if file_name.is_relative() {
 +                sess.local_crate_source_file
 +                    .as_deref()
 +                    .and_then(Path::parent)
 +                    .unwrap_or_else(|| Path::new(""))
 +                    .join(file_name)
 +            } else {
 +                file_name
 +            };
 +
 +            let (conf, errors) = utils::conf::read(&file_name);
 +
 +            // all conf errors are non-fatal, we just use the default conf in case of error
 +            for error in errors {
 +                sess.struct_err(&format!(
 +                    "error reading Clippy's configuration file `{}`: {}",
 +                    file_name.display(),
 +                    error
 +                ))
 +                .emit();
 +            }
 +
 +            conf
 +        },
 +        Err((err, span)) => {
 +            sess.struct_span_err(span, err)
 +                .span_note(span, "Clippy will use default configuration")
 +                .emit();
 +            Conf::default()
 +        },
 +    }
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +#[rustfmt::skip]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
 +    // begin deprecated lints, do not remove this comment, it’s used in `update_lints`
 +    store.register_removed(
 +        "clippy::should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "clippy::extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "clippy::range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "clippy::unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "clippy::unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "clippy::misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "clippy::assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "clippy::if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "clippy::unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "clippy::invalid_ref",
 +        "superseded by rustc lint `invalid_value`",
 +    );
 +    store.register_removed(
 +        "clippy::unused_collect",
 +        "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint",
 +    );
 +    store.register_removed(
 +        "clippy::into_iter_on_array",
 +        "this lint has been uplifted to rustc and is now called `array_into_iter`",
 +    );
 +    store.register_removed(
 +        "clippy::unused_label",
 +        "this lint has been uplifted to rustc and is now called `unused_labels`",
 +    );
 +    store.register_removed(
 +        "clippy::replace_consts",
 +        "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants",
 +    );
 +    store.register_removed(
 +        "clippy::regex_macro",
 +        "the regex! macro has been removed from the regex crate in 2018",
 +    );
 +    store.register_removed(
 +        "clippy::drop_bounds",
 +        "this lint has been uplifted to rustc and is now called `drop_bounds`",
 +    );
 +    store.register_removed(
 +        "clippy::temporary_cstring_as_ptr",
 +        "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`",
 +    );
 +    store.register_removed(
 +        "clippy::panic_params",
 +        "this lint has been uplifted to rustc and is now called `panic_fmt`",
 +    );
 +    store.register_removed(
 +        "clippy::unknown_clippy_lints",
 +        "this lint has been integrated into the `unknown_lints` rustc lint",
 +    );
 +    store.register_removed(
 +        "clippy::find_map",
 +        "this lint has been replaced by `manual_find_map`, a more specific lint",
 +    );
 +    // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 +
 +    // begin register lints, do not remove this comment, it’s used in `update_lints`
 +    store.register_lints(&[
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::CLIPPY_LINTS_INTERNAL,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::COMPILER_LINT_FUNCTIONS,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::DEFAULT_LINT,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::INTERNING_DEFINED_SYMBOL,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::INVALID_PATHS,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::LINT_WITHOUT_LINT_PASS,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::PRODUCE_ICE,
 +        #[cfg(feature = "internal-lints")]
 +        &utils::internal_lints::UNNECESSARY_SYMBOL_STR,
 +        &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,
 +        &atomic_ordering::INVALID_ATOMIC_ORDERING,
 +        &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
 +        &attrs::DEPRECATED_CFG_ATTR,
 +        &attrs::DEPRECATED_SEMVER,
 +        &attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
 +        &attrs::INLINE_ALWAYS,
 +        &attrs::MISMATCHED_TARGET_OS,
 +        &attrs::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,
 +        &booleans::LOGIC_BUG,
 +        &booleans::NONMINIMAL_BOOL,
 +        &bytecount::NAIVE_BYTECOUNT,
 +        &cargo_common_metadata::CARGO_COMMON_METADATA,
 +        &case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
 +        &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::IFS_SAME_COND,
 +        &copies::IF_SAME_THEN_ELSE,
 +        &copies::SAME_FUNCTIONS_IN_IF_CONDITION,
 +        &copy_iterator::COPY_ITERATOR,
 +        &create_dir::CREATE_DIR,
 +        &dbg_macro::DBG_MACRO,
 +        &default::DEFAULT_TRAIT_ACCESS,
 +        &default::FIELD_REASSIGN_WITH_DEFAULT,
 +        &dereference::EXPLICIT_DEREF_METHODS,
 +        &derive::DERIVE_HASH_XOR_EQ,
 +        &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
 +        &derive::EXPL_IMPL_CLONE_ON_COPY,
 +        &derive::UNSAFE_DERIVE_DESERIALIZE,
 +        &disallowed_method::DISALLOWED_METHOD,
 +        &doc::DOC_MARKDOWN,
 +        &doc::MISSING_ERRORS_DOC,
++        &doc::MISSING_PANICS_DOC,
 +        &doc::MISSING_SAFETY_DOC,
 +        &doc::NEEDLESS_DOCTEST_MAIN,
 +        &double_comparison::DOUBLE_COMPARISONS,
 +        &double_parens::DOUBLE_PARENS,
 +        &drop_forget_ref::DROP_COPY,
 +        &drop_forget_ref::DROP_REF,
 +        &drop_forget_ref::FORGET_COPY,
 +        &drop_forget_ref::FORGET_REF,
 +        &duration_subsec::DURATION_SUBSEC,
 +        &else_if_without_else::ELSE_IF_WITHOUT_ELSE,
 +        &empty_enum::EMPTY_ENUM,
 +        &entry::MAP_ENTRY,
 +        &enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
 +        &enum_variants::ENUM_VARIANT_NAMES,
 +        &enum_variants::MODULE_INCEPTION,
 +        &enum_variants::MODULE_NAME_REPETITIONS,
 +        &enum_variants::PUB_ENUM_VARIANT_NAMES,
 +        &eq_op::EQ_OP,
 +        &eq_op::OP_REF,
 +        &erasing_op::ERASING_OP,
 +        &escape::BOXED_LOCAL,
 +        &eta_reduction::REDUNDANT_CLOSURE,
 +        &eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
 +        &eval_order_dependence::DIVERGING_SUB_EXPRESSION,
 +        &eval_order_dependence::EVAL_ORDER_DEPENDENCE,
 +        &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
 +        &excessive_bools::STRUCT_EXCESSIVE_BOOLS,
 +        &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,
 +        &formatting::POSSIBLE_MISSING_COMMA,
 +        &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
 +        &formatting::SUSPICIOUS_ELSE_FORMATTING,
 +        &formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
 +        &from_over_into::FROM_OVER_INTO,
 +        &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_let_some_result::IF_LET_SOME_RESULT,
 +        &if_not_else::IF_NOT_ELSE,
 +        &implicit_return::IMPLICIT_RETURN,
 +        &implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
 +        &indexing_slicing::INDEXING_SLICING,
 +        &indexing_slicing::OUT_OF_BOUNDS_INDEXING,
 +        &infinite_iter::INFINITE_ITER,
 +        &infinite_iter::MAYBE_INFINITE_ITER,
 +        &inherent_impl::MULTIPLE_INHERENT_IMPL,
 +        &inherent_to_string::INHERENT_TO_STRING,
 +        &inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
 +        &inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
 +        &int_plus_one::INT_PLUS_ONE,
 +        &integer_division::INTEGER_DIVISION,
 +        &items_after_statements::ITEMS_AFTER_STATEMENTS,
 +        &large_const_arrays::LARGE_CONST_ARRAYS,
 +        &large_enum_variant::LARGE_ENUM_VARIANT,
 +        &large_stack_arrays::LARGE_STACK_ARRAYS,
 +        &len_zero::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_MEMCPY,
 +        &loops::MUT_RANGE_BOUND,
 +        &loops::NEEDLESS_COLLECT,
 +        &loops::NEEDLESS_RANGE_LOOP,
 +        &loops::NEVER_LOOP,
 +        &loops::SAME_ITEM_PUSH,
 +        &loops::SINGLE_ELEMENT_LOOP,
 +        &loops::WHILE_IMMUTABLE_CONDITION,
 +        &loops::WHILE_LET_LOOP,
 +        &loops::WHILE_LET_ON_ITERATOR,
 +        &macro_use::MACRO_USE_IMPORTS,
 +        &main_recursion::MAIN_RECURSION,
 +        &manual_async_fn::MANUAL_ASYNC_FN,
 +        &manual_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_identity::MAP_IDENTITY,
 +        &map_unit_fn::OPTION_MAP_UNIT_FN,
 +        &map_unit_fn::RESULT_MAP_UNIT_FN,
 +        &match_on_vec_items::MATCH_ON_VEC_ITEMS,
 +        &matches::INFALLIBLE_DESTRUCTURING_MATCH,
 +        &matches::MATCH_AS_REF,
 +        &matches::MATCH_BOOL,
 +        &matches::MATCH_LIKE_MATCHES_MACRO,
 +        &matches::MATCH_OVERLAPPING_ARM,
 +        &matches::MATCH_REF_PATS,
 +        &matches::MATCH_SAME_ARMS,
 +        &matches::MATCH_SINGLE_BINDING,
 +        &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +        &matches::MATCH_WILD_ERR_ARM,
 +        &matches::REDUNDANT_PATTERN_MATCHING,
 +        &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +        &matches::SINGLE_MATCH,
 +        &matches::SINGLE_MATCH_ELSE,
 +        &matches::WILDCARD_ENUM_MATCH_ARM,
 +        &matches::WILDCARD_IN_OR_PATTERNS,
 +        &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
 +        &mem_forget::MEM_FORGET,
 +        &mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
 +        &mem_replace::MEM_REPLACE_WITH_DEFAULT,
 +        &mem_replace::MEM_REPLACE_WITH_UNINIT,
 +        &methods::BIND_INSTEAD_OF_MAP,
 +        &methods::CHARS_LAST_CMP,
 +        &methods::CHARS_NEXT_CMP,
 +        &methods::CLONE_DOUBLE_REF,
 +        &methods::CLONE_ON_COPY,
 +        &methods::CLONE_ON_REF_PTR,
 +        &methods::EXPECT_FUN_CALL,
 +        &methods::EXPECT_USED,
 +        &methods::FILETYPE_IS_FILE,
 +        &methods::FILTER_MAP,
 +        &methods::FILTER_MAP_NEXT,
 +        &methods::FILTER_NEXT,
 +        &methods::FLAT_MAP_IDENTITY,
 +        &methods::FROM_ITER_INSTEAD_OF_COLLECT,
 +        &methods::GET_UNWRAP,
 +        &methods::INEFFICIENT_TO_STRING,
 +        &methods::INSPECT_FOR_EACH,
 +        &methods::INTO_ITER_ON_REF,
 +        &methods::ITERATOR_STEP_BY_ZERO,
 +        &methods::ITER_CLONED_COLLECT,
 +        &methods::ITER_NEXT_SLICE,
 +        &methods::ITER_NTH,
 +        &methods::ITER_NTH_ZERO,
 +        &methods::ITER_SKIP_NEXT,
 +        &methods::MANUAL_FILTER_MAP,
 +        &methods::MANUAL_FIND_MAP,
 +        &methods::MANUAL_SATURATING_ARITHMETIC,
 +        &methods::MAP_COLLECT_RESULT_UNIT,
 +        &methods::MAP_FLATTEN,
 +        &methods::MAP_UNWRAP_OR,
 +        &methods::NEW_RET_NO_SELF,
 +        &methods::OK_EXPECT,
 +        &methods::OPTION_AS_REF_DEREF,
 +        &methods::OPTION_MAP_OR_NONE,
 +        &methods::OR_FUN_CALL,
 +        &methods::RESULT_MAP_OR_INTO_OPTION,
 +        &methods::SEARCH_IS_SOME,
 +        &methods::SHOULD_IMPLEMENT_TRAIT,
 +        &methods::SINGLE_CHAR_ADD_STR,
 +        &methods::SINGLE_CHAR_PATTERN,
 +        &methods::SKIP_WHILE_NEXT,
 +        &methods::STRING_EXTEND_CHARS,
 +        &methods::SUSPICIOUS_MAP,
 +        &methods::UNINIT_ASSUMED_INIT,
 +        &methods::UNNECESSARY_FILTER_MAP,
 +        &methods::UNNECESSARY_FOLD,
 +        &methods::UNNECESSARY_LAZY_EVALUATIONS,
 +        &methods::UNWRAP_USED,
 +        &methods::USELESS_ASREF,
 +        &methods::WRONG_PUB_SELF_CONVENTION,
 +        &methods::WRONG_SELF_CONVENTION,
 +        &methods::ZST_OFFSET,
 +        &minmax::MIN_MAX,
 +        &misc::CMP_NAN,
 +        &misc::CMP_OWNED,
 +        &misc::FLOAT_CMP,
 +        &misc::FLOAT_CMP_CONST,
 +        &misc::MODULO_ONE,
 +        &misc::SHORT_CIRCUIT_STATEMENT,
 +        &misc::TOPLEVEL_REF_ARG,
 +        &misc::USED_UNDERSCORE_BINDING,
 +        &misc::ZERO_PTR,
 +        &misc_early::BUILTIN_TYPE_SHADOW,
 +        &misc_early::DOUBLE_NEG,
 +        &misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
 +        &misc_early::MIXED_CASE_HEX_LITERALS,
 +        &misc_early::REDUNDANT_PATTERN,
 +        &misc_early::UNNEEDED_FIELD_PATTERN,
 +        &misc_early::UNNEEDED_WILDCARD_PATTERN,
 +        &misc_early::UNSEPARATED_LITERAL_SUFFIX,
 +        &misc_early::ZERO_PREFIXED_LITERAL,
 +        &missing_const_for_fn::MISSING_CONST_FOR_FN,
 +        &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
 +        &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
 +        &modulo_arithmetic::MODULO_ARITHMETIC,
 +        &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
 +        &mut_key::MUTABLE_KEY_TYPE,
 +        &mut_mut::MUT_MUT,
 +        &mut_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_bool::BOOL_COMPARISON,
 +        &needless_bool::NEEDLESS_BOOL,
 +        &needless_borrow::NEEDLESS_BORROW,
 +        &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
 +        &needless_continue::NEEDLESS_CONTINUE,
 +        &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
 +        &needless_question_mark::NEEDLESS_QUESTION_MARK,
 +        &needless_update::NEEDLESS_UPDATE,
 +        &neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
 +        &neg_multiply::NEG_MULTIPLY,
 +        &new_without_default::NEW_WITHOUT_DEFAULT,
 +        &no_effect::NO_EFFECT,
 +        &no_effect::UNNECESSARY_OPERATION,
 +        &non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
 +        &non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
 +        &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
 +        &non_expressive_names::MANY_SINGLE_CHAR_NAMES,
 +        &non_expressive_names::SIMILAR_NAMES,
 +        &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::MUT_FROM_REF,
 +        &ptr::PTR_ARG,
 +        &ptr_eq::PTR_EQ,
 +        &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
 +        &question_mark::QUESTION_MARK,
 +        &ranges::MANUAL_RANGE_CONTAINS,
 +        &ranges::RANGE_MINUS_ONE,
 +        &ranges::RANGE_PLUS_ONE,
 +        &ranges::RANGE_ZIP_WITH_LEN,
 +        &ranges::REVERSED_EMPTY_RANGES,
 +        &redundant_clone::REDUNDANT_CLONE,
 +        &redundant_closure_call::REDUNDANT_CLOSURE_CALL,
 +        &redundant_else::REDUNDANT_ELSE,
 +        &redundant_field_names::REDUNDANT_FIELD_NAMES,
 +        &redundant_pub_crate::REDUNDANT_PUB_CRATE,
 +        &redundant_slicing::REDUNDANT_SLICING,
 +        &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
 +        &ref_option_ref::REF_OPTION_REF,
 +        &reference::DEREF_ADDROF,
 +        &reference::REF_IN_DEREF,
 +        &regex::INVALID_REGEX,
 +        &regex::TRIVIAL_REGEX,
 +        &repeat_once::REPEAT_ONCE,
 +        &returns::LET_AND_RETURN,
 +        &returns::NEEDLESS_RETURN,
 +        &self_assignment::SELF_ASSIGNMENT,
 +        &serde_api::SERDE_API_MISUSE,
 +        &shadow::SHADOW_REUSE,
 +        &shadow::SHADOW_SAME,
 +        &shadow::SHADOW_UNRELATED,
 +        &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
 +        &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
 +        &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
 +        &stable_sort_primitive::STABLE_SORT_PRIMITIVE,
 +        &strings::STRING_ADD,
 +        &strings::STRING_ADD_ASSIGN,
 +        &strings::STRING_FROM_UTF8_AS_BYTES,
 +        &strings::STRING_LIT_AS_BYTES,
 +        &strings::STRING_TO_STRING,
 +        &strings::STR_TO_STRING,
 +        &suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
 +        &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
 +        &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
 +        &swap::ALMOST_SWAPPED,
 +        &swap::MANUAL_SWAP,
 +        &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
 +        &temporary_assignment::TEMPORARY_ASSIGNMENT,
 +        &to_digit_is_some::TO_DIGIT_IS_SOME,
 +        &to_string_in_display::TO_STRING_IN_DISPLAY,
 +        &trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
 +        &trait_bounds::TYPE_REPETITION_IN_BOUNDS,
 +        &transmute::CROSSPOINTER_TRANSMUTE,
 +        &transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +        &transmute::TRANSMUTE_BYTES_TO_STR,
 +        &transmute::TRANSMUTE_FLOAT_TO_INT,
 +        &transmute::TRANSMUTE_INT_TO_BOOL,
 +        &transmute::TRANSMUTE_INT_TO_CHAR,
 +        &transmute::TRANSMUTE_INT_TO_FLOAT,
 +        &transmute::TRANSMUTE_PTR_TO_PTR,
 +        &transmute::TRANSMUTE_PTR_TO_REF,
 +        &transmute::UNSOUND_COLLECTION_TRANSMUTE,
 +        &transmute::USELESS_TRANSMUTE,
 +        &transmute::WRONG_TRANSMUTE,
 +        &transmuting_null::TRANSMUTING_NULL,
 +        &try_err::TRY_ERR,
 +        &types::ABSURD_EXTREME_COMPARISONS,
 +        &types::BORROWED_BOX,
 +        &types::BOX_VEC,
 +        &types::CAST_LOSSLESS,
 +        &types::CAST_POSSIBLE_TRUNCATION,
 +        &types::CAST_POSSIBLE_WRAP,
 +        &types::CAST_PRECISION_LOSS,
 +        &types::CAST_PTR_ALIGNMENT,
 +        &types::CAST_REF_TO_MUT,
 +        &types::CAST_SIGN_LOSS,
 +        &types::CHAR_LIT_AS_U8,
 +        &types::FN_TO_NUMERIC_CAST,
 +        &types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +        &types::IMPLICIT_HASHER,
 +        &types::INVALID_UPCAST_COMPARISONS,
 +        &types::LET_UNIT_VALUE,
 +        &types::LINKEDLIST,
 +        &types::OPTION_OPTION,
 +        &types::PTR_AS_PTR,
 +        &types::RC_BUFFER,
 +        &types::REDUNDANT_ALLOCATION,
 +        &types::TYPE_COMPLEXITY,
 +        &types::UNIT_ARG,
 +        &types::UNIT_CMP,
 +        &types::UNNECESSARY_CAST,
 +        &types::VEC_BOX,
 +        &undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
 +        &unicode::INVISIBLE_CHARACTERS,
 +        &unicode::NON_ASCII_LITERAL,
 +        &unicode::UNICODE_NOT_NFC,
 +        &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
 +        &unnamed_address::FN_ADDRESS_COMPARISONS,
 +        &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
 +        &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_io_amount::UNUSED_IO_AMOUNT,
 +        &unused_self::UNUSED_SELF,
 +        &unused_unit::UNUSED_UNIT,
 +        &unwrap::PANICKING_UNWRAP,
 +        &unwrap::UNNECESSARY_UNWRAP,
 +        &unwrap_in_result::UNWRAP_IN_RESULT,
 +        &upper_case_acronyms::UPPER_CASE_ACRONYMS,
 +        &use_self::USE_SELF,
 +        &useless_conversion::USELESS_CONVERSION,
 +        &vec::USELESS_VEC,
 +        &vec_init_then_push::VEC_INIT_THEN_PUSH,
 +        &vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
 +        &verbose_file_reads::VERBOSE_FILE_READS,
 +        &wildcard_dependencies::WILDCARD_DEPENDENCIES,
 +        &wildcard_imports::ENUM_GLOB_USE,
 +        &wildcard_imports::WILDCARD_IMPORTS,
 +        &write::PRINTLN_EMPTY_STRING,
 +        &write::PRINT_LITERAL,
 +        &write::PRINT_STDERR,
 +        &write::PRINT_STDOUT,
 +        &write::PRINT_WITH_NEWLINE,
 +        &write::USE_DEBUG,
 +        &write::WRITELN_EMPTY_STRING,
 +        &write::WRITE_LITERAL,
 +        &write::WRITE_WITH_NEWLINE,
 +        &zero_div_zero::ZERO_DIVIDED_BY_ZERO,
 +        &zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
 +    ]);
 +    // end register lints, do not remove this comment, it’s used in `update_lints`
 +
 +    // all the internal lints
 +    #[cfg(feature = "internal-lints")]
 +    {
 +        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
 +        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
 +        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
 +        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
 +        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
 +        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
 +        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
 +        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
 +        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
 +        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
 +    }
 +    store.register_late_pass(|| box utils::author::Author);
 +    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
 +    store.register_late_pass(|| box serde_api::SerdeApi);
 +    let vec_box_size_threshold = conf.vec_box_size_threshold;
 +    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
 +    store.register_late_pass(|| box booleans::NonminimalBool);
 +    store.register_late_pass(|| box eq_op::EqOp);
 +    store.register_late_pass(|| box enum_clike::UnportableVariant);
 +    store.register_late_pass(|| box float_literal::FloatLiteral);
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
 +    store.register_late_pass(|| box ptr::Ptr);
 +    store.register_late_pass(|| box ptr_eq::PtrEq);
 +    store.register_late_pass(|| box needless_bool::NeedlessBool);
 +    store.register_late_pass(|| box needless_bool::BoolComparison);
 +    store.register_late_pass(|| box approx_const::ApproxConstant);
 +    store.register_late_pass(|| box misc::MiscLints);
 +    store.register_late_pass(|| box eta_reduction::EtaReduction);
 +    store.register_late_pass(|| box identity_op::IdentityOp);
 +    store.register_late_pass(|| box erasing_op::ErasingOp);
 +    store.register_late_pass(|| box mut_mut::MutMut);
 +    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
 +    store.register_late_pass(|| box len_zero::LenZero);
 +    store.register_late_pass(|| box attrs::Attributes);
 +    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
 +    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
 +    store.register_late_pass(|| box unicode::Unicode);
 +    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
 +    store.register_late_pass(|| box strings::StringAdd);
 +    store.register_late_pass(|| box implicit_return::ImplicitReturn);
 +    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
 +
 +    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_late_pass(move || box methods::Methods::new(msrv));
 +    store.register_late_pass(move || box matches::Matches::new(msrv));
 +    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
 +    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
 +    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
 +    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
 +    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
 +    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
 +    store.register_late_pass(move || box ranges::Ranges::new(msrv));
 +    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
 +    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
 +    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
 +    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark::new(msrv));
 +
 +    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
 +    store.register_late_pass(|| box map_clone::MapClone);
 +    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
 +    store.register_late_pass(|| box shadow::Shadow);
 +    store.register_late_pass(|| box types::LetUnitValue);
 +    store.register_late_pass(|| box types::UnitCmp);
 +    store.register_late_pass(|| box loops::Loops);
 +    store.register_late_pass(|| box main_recursion::MainRecursion::default());
 +    store.register_late_pass(|| box lifetimes::Lifetimes);
 +    store.register_late_pass(|| box entry::HashMapPass);
 +    store.register_late_pass(|| box types::Casts);
 +    let type_complexity_threshold = conf.type_complexity_threshold;
 +    store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
 +    store.register_late_pass(|| box minmax::MinMaxPass);
 +    store.register_late_pass(|| box open_options::OpenOptions);
 +    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
 +    store.register_late_pass(|| box mutex_atomic::Mutex);
 +    store.register_late_pass(|| box needless_update::NeedlessUpdate);
 +    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
 +    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
 +    store.register_late_pass(|| box no_effect::NoEffect);
 +    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
 +    store.register_late_pass(|| box transmute::Transmute);
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
 +    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
 +    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
 +    store.register_late_pass(|| box strings::StringLitAsBytes);
 +    store.register_late_pass(|| box derive::Derive);
 +    store.register_late_pass(|| box types::CharLitAsU8);
 +    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
 +    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
 +    store.register_late_pass(|| box empty_enum::EmptyEnum);
 +    store.register_late_pass(|| box types::AbsurdExtremeComparisons);
 +    store.register_late_pass(|| box types::InvalidUpcastComparisons);
 +    store.register_late_pass(|| box regex::Regex::default());
 +    store.register_late_pass(|| box copies::CopyAndPaste);
 +    store.register_late_pass(|| box copy_iterator::CopyIterator);
 +    store.register_late_pass(|| box format::UselessFormat);
 +    store.register_late_pass(|| box swap::Swap);
 +    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
 +    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
 +    let too_many_arguments_threshold1 = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold2 = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold1, too_many_lines_threshold2));
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
 +    store.register_late_pass(|| box neg_multiply::NegMultiply);
 +    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
 +    store.register_late_pass(|| box mem_forget::MemForget);
 +    store.register_late_pass(|| box arithmetic::Arithmetic::default());
 +    store.register_late_pass(|| box assign_ops::AssignOps);
 +    store.register_late_pass(|| box let_if_seq::LetIfSeq);
 +    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
 +    store.register_late_pass(|| box missing_doc::MissingDoc::new());
 +    store.register_late_pass(|| box missing_inline::MissingInline);
 +    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
 +    store.register_late_pass(|| box if_let_some_result::OkIfLet);
 +    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
 +    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
 +    store.register_late_pass(|| box explicit_write::ExplicitWrite);
 +    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
 +    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
 +        conf.trivial_copy_size_limit,
 +        conf.pass_by_value_size_limit,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move || box pass_by_ref_or_value);
 +    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
 +    store.register_late_pass(|| box try_err::TryErr);
 +    store.register_late_pass(|| box bytecount::ByteCount);
 +    store.register_late_pass(|| box infinite_iter::InfiniteIter);
 +    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
 +    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
 +    store.register_late_pass(|| box types::ImplicitHasher);
 +    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
 +    store.register_late_pass(|| box types::UnitArg);
 +    store.register_late_pass(|| box double_comparison::DoubleComparisons);
 +    store.register_late_pass(|| box question_mark::QuestionMark);
 +    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
 +    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
 +    store.register_late_pass(|| box map_unit_fn::MapUnit);
 +    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default());
 +    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
 +    store.register_late_pass(|| box unwrap::Unwrap);
 +    store.register_late_pass(|| box duration_subsec::DurationSubsec);
 +    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
 +    store.register_late_pass(|| box non_copy_const::NonCopyConst);
 +    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
 +    store.register_late_pass(|| box redundant_clone::RedundantClone);
 +    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
 +    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
 +    store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
 +    store.register_late_pass(|| box types::RefToMut);
 +    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
 +    store.register_late_pass(|| box transmuting_null::TransmutingNull);
 +    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
 +    store.register_late_pass(|| box integer_division::IntegerDivision);
 +    store.register_late_pass(|| box inherent_to_string::InherentToString);
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
 +    store.register_late_pass(|| box comparison_chain::ComparisonChain);
 +    store.register_late_pass(|| box mut_key::MutableKeyType);
 +    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
 +    store.register_early_pass(|| box reference::DerefAddrOf);
 +    store.register_early_pass(|| box reference::RefInDeref);
 +    store.register_early_pass(|| box double_parens::DoubleParens);
 +    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
 +    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
 +    store.register_early_pass(|| box if_not_else::IfNotElse);
 +    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
 +    store.register_early_pass(|| box int_plus_one::IntPlusOne);
 +    store.register_early_pass(|| box formatting::Formatting);
 +    store.register_early_pass(|| box misc_early::MiscEarlyLints);
 +    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
 +    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
 +    store.register_early_pass(|| box unused_unit::UnusedUnit);
 +    store.register_late_pass(|| box returns::Return);
 +    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
 +    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
 +    store.register_early_pass(|| box precedence::Precedence);
 +    store.register_early_pass(|| box needless_continue::NeedlessContinue);
 +    store.register_early_pass(|| box redundant_else::RedundantElse);
 +    store.register_late_pass(|| box create_dir::CreateDir);
 +    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
 +    store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
 +    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
 +    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
 +    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
 +    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
 +    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
 +    store.register_early_pass(|| box upper_case_acronyms::UpperCaseAcronyms);
 +    store.register_late_pass(|| box default::Default::default());
 +    store.register_late_pass(|| box unused_self::UnusedSelf);
 +    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
 +    store.register_late_pass(|| box exit::Exit);
 +    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
 +    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
 +    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
 +    store.register_early_pass(|| box as_conversions::AsConversions);
 +    store.register_late_pass(|| box let_underscore::LetUnderscore);
 +    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
 +    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
 +    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
 +    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
 +    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
 +    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
 +    store.register_late_pass(|| box dereference::Dereferencing);
 +    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
 +    store.register_late_pass(|| box future_not_send::FutureNotSend);
 +    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
 +    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
 +    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
 +    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
 +    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
 +    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
 +        single_char_binding_names_threshold,
 +    });
 +    store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
 +    store.register_late_pass(|| box macro_use::MacroUseImports::default());
 +    store.register_late_pass(|| box map_identity::MapIdentity);
 +    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
 +    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
 +    store.register_late_pass(|| box repeat_once::RepeatOnce);
 +    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
 +    store.register_late_pass(|| box self_assignment::SelfAssignment);
 +    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
 +    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
 +    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
 +    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
 +    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
 +    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
 +    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
 +    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
 +    store.register_late_pass(|| box strings::StrToString);
 +    store.register_late_pass(|| box strings::StringToString);
 +    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
 +    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
 +    store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
 +    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
 +    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
 +
 +    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +        LintId::of(&arithmetic::FLOAT_ARITHMETIC),
 +        LintId::of(&arithmetic::INTEGER_ARITHMETIC),
 +        LintId::of(&as_conversions::AS_CONVERSIONS),
 +        LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
 +        LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
 +        LintId::of(&create_dir::CREATE_DIR),
 +        LintId::of(&dbg_macro::DBG_MACRO),
 +        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +        LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
 +        LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
 +        LintId::of(&exit::EXIT),
 +        LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
 +        LintId::of(&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(&methods::WRONG_PUB_SELF_CONVENTION),
 +        LintId::of(&misc::FLOAT_CMP_CONST),
 +        LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN),
 +        LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
 +        LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
 +        LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC),
 +        LintId::of(&panic_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(&shadow::SHADOW_REUSE),
 +        LintId::of(&shadow::SHADOW_SAME),
 +        LintId::of(&strings::STRING_ADD),
 +        LintId::of(&strings::STRING_TO_STRING),
 +        LintId::of(&strings::STR_TO_STRING),
 +        LintId::of(&types::RC_BUFFER),
 +        LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
 +        LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
 +        LintId::of(&write::PRINT_STDERR),
 +        LintId::of(&write::PRINT_STDOUT),
 +        LintId::of(&write::USE_DEBUG),
 +    ]);
 +
 +    store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
 +        LintId::of(&attrs::INLINE_ALWAYS),
 +        LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
 +        LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
 +        LintId::of(&bit_mask::VERBOSE_BIT_MASK),
 +        LintId::of(&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
 +        LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
 +        LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
 +        LintId::of(&copy_iterator::COPY_ITERATOR),
 +        LintId::of(&default::DEFAULT_TRAIT_ACCESS),
 +        LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
 +        LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
 +        LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
 +        LintId::of(&doc::DOC_MARKDOWN),
 +        LintId::of(&doc::MISSING_ERRORS_DOC),
++        LintId::of(&doc::MISSING_PANICS_DOC),
 +        LintId::of(&empty_enum::EMPTY_ENUM),
 +        LintId::of(&enum_variants::MODULE_NAME_REPETITIONS),
 +        LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES),
 +        LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
 +        LintId::of(&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
 +        LintId::of(&excessive_bools::STRUCT_EXCESSIVE_BOOLS),
 +        LintId::of(&functions::MUST_USE_CANDIDATE),
 +        LintId::of(&functions::TOO_MANY_LINES),
 +        LintId::of(&if_not_else::IF_NOT_ELSE),
 +        LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
 +        LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
 +        LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
 +        LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
 +        LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
 +        LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
 +        LintId::of(&literal_representation::UNREADABLE_LITERAL),
 +        LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
 +        LintId::of(&loops::EXPLICIT_ITER_LOOP),
 +        LintId::of(&macro_use::MACRO_USE_IMPORTS),
 +        LintId::of(&manual_ok_or::MANUAL_OK_OR),
 +        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
 +        LintId::of(&matches::MATCH_BOOL),
 +        LintId::of(&matches::MATCH_SAME_ARMS),
 +        LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
 +        LintId::of(&matches::MATCH_WILD_ERR_ARM),
 +        LintId::of(&matches::SINGLE_MATCH_ELSE),
 +        LintId::of(&methods::FILTER_MAP),
 +        LintId::of(&methods::FILTER_MAP_NEXT),
 +        LintId::of(&methods::INEFFICIENT_TO_STRING),
 +        LintId::of(&methods::MAP_FLATTEN),
 +        LintId::of(&methods::MAP_UNWRAP_OR),
 +        LintId::of(&misc::USED_UNDERSCORE_BINDING),
 +        LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX),
 +        LintId::of(&mut_mut::MUT_MUT),
 +        LintId::of(&needless_continue::NEEDLESS_CONTINUE),
 +        LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
 +        LintId::of(&non_expressive_names::SIMILAR_NAMES),
 +        LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
 +        LintId::of(&pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
 +        LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
 +        LintId::of(&ranges::RANGE_MINUS_ONE),
 +        LintId::of(&ranges::RANGE_PLUS_ONE),
 +        LintId::of(&redundant_else::REDUNDANT_ELSE),
 +        LintId::of(&ref_option_ref::REF_OPTION_REF),
 +        LintId::of(&shadow::SHADOW_UNRELATED),
 +        LintId::of(&strings::STRING_ADD_ASSIGN),
 +        LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
 +        LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
 +        LintId::of(&types::CAST_LOSSLESS),
 +        LintId::of(&types::CAST_POSSIBLE_TRUNCATION),
 +        LintId::of(&types::CAST_POSSIBLE_WRAP),
 +        LintId::of(&types::CAST_PRECISION_LOSS),
 +        LintId::of(&types::CAST_PTR_ALIGNMENT),
 +        LintId::of(&types::CAST_SIGN_LOSS),
 +        LintId::of(&types::IMPLICIT_HASHER),
 +        LintId::of(&types::INVALID_UPCAST_COMPARISONS),
 +        LintId::of(&types::LET_UNIT_VALUE),
 +        LintId::of(&types::LINKEDLIST),
 +        LintId::of(&types::OPTION_OPTION),
 +        LintId::of(&types::PTR_AS_PTR),
 +        LintId::of(&unicode::NON_ASCII_LITERAL),
 +        LintId::of(&unicode::UNICODE_NOT_NFC),
 +        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
 +        LintId::of(&unused_self::UNUSED_SELF),
 +        LintId::of(&wildcard_imports::ENUM_GLOB_USE),
 +        LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
 +        LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
 +    ]);
 +
 +    #[cfg(feature = "internal-lints")]
 +    store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
 +        LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL),
 +        LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
 +        LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS),
 +        LintId::of(&utils::internal_lints::DEFAULT_LINT),
 +        LintId::of(&utils::internal_lints::INTERNING_DEFINED_SYMBOL),
 +        LintId::of(&utils::internal_lints::INVALID_PATHS),
 +        LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS),
 +        LintId::of(&utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
 +        LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA),
 +        LintId::of(&utils::internal_lints::PRODUCE_ICE),
 +        LintId::of(&utils::internal_lints::UNNECESSARY_SYMBOL_STR),
 +    ]);
 +
 +    store.register_group(true, "clippy::all", Some("clippy"), vec![
 +        LintId::of(&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(&atomic_ordering::INVALID_ATOMIC_ORDERING),
 +        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +        LintId::of(&attrs::DEPRECATED_CFG_ATTR),
 +        LintId::of(&attrs::DEPRECATED_SEMVER),
 +        LintId::of(&attrs::MISMATCHED_TARGET_OS),
 +        LintId::of(&attrs::USELESS_ATTRIBUTE),
 +        LintId::of(&bit_mask::BAD_BIT_MASK),
 +        LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
 +        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
 +        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +        LintId::of(&booleans::LOGIC_BUG),
 +        LintId::of(&booleans::NONMINIMAL_BOOL),
 +        LintId::of(&bytecount::NAIVE_BYTECOUNT),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
 +        LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
 +        LintId::of(&comparison_chain::COMPARISON_CHAIN),
 +        LintId::of(&copies::IFS_SAME_COND),
 +        LintId::of(&copies::IF_SAME_THEN_ELSE),
 +        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
 +        LintId::of(&derive::DERIVE_HASH_XOR_EQ),
 +        LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +        LintId::of(&doc::MISSING_SAFETY_DOC),
 +        LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
 +        LintId::of(&double_comparison::DOUBLE_COMPARISONS),
 +        LintId::of(&double_parens::DOUBLE_PARENS),
 +        LintId::of(&drop_forget_ref::DROP_COPY),
 +        LintId::of(&drop_forget_ref::DROP_REF),
 +        LintId::of(&drop_forget_ref::FORGET_COPY),
 +        LintId::of(&drop_forget_ref::FORGET_REF),
 +        LintId::of(&duration_subsec::DURATION_SUBSEC),
 +        LintId::of(&entry::MAP_ENTRY),
 +        LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +        LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
 +        LintId::of(&enum_variants::MODULE_INCEPTION),
 +        LintId::of(&eq_op::EQ_OP),
 +        LintId::of(&eq_op::OP_REF),
 +        LintId::of(&erasing_op::ERASING_OP),
 +        LintId::of(&escape::BOXED_LOCAL),
 +        LintId::of(&eta_reduction::REDUNDANT_CLOSURE),
 +        LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +        LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +        LintId::of(&explicit_write::EXPLICIT_WRITE),
 +        LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +        LintId::of(&float_literal::EXCESSIVE_PRECISION),
 +        LintId::of(&format::USELESS_FORMAT),
 +        LintId::of(&formatting::POSSIBLE_MISSING_COMMA),
 +        LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +        LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
 +        LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +        LintId::of(&from_over_into::FROM_OVER_INTO),
 +        LintId::of(&functions::DOUBLE_MUST_USE),
 +        LintId::of(&functions::MUST_USE_UNIT),
 +        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +        LintId::of(&functions::RESULT_UNIT_ERR),
 +        LintId::of(&functions::TOO_MANY_ARGUMENTS),
 +        LintId::of(&get_last_with_len::GET_LAST_WITH_LEN),
 +        LintId::of(&identity_op::IDENTITY_OP),
 +        LintId::of(&if_let_mutex::IF_LET_MUTEX),
 +        LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
 +        LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +        LintId::of(&infinite_iter::INFINITE_ITER),
 +        LintId::of(&inherent_to_string::INHERENT_TO_STRING),
 +        LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
 +        LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +        LintId::of(&int_plus_one::INT_PLUS_ONE),
 +        LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
 +        LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
 +        LintId::of(&len_zero::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_MEMCPY),
 +        LintId::of(&loops::MUT_RANGE_BOUND),
 +        LintId::of(&loops::NEEDLESS_COLLECT),
 +        LintId::of(&loops::NEEDLESS_RANGE_LOOP),
 +        LintId::of(&loops::NEVER_LOOP),
 +        LintId::of(&loops::SAME_ITEM_PUSH),
 +        LintId::of(&loops::SINGLE_ELEMENT_LOOP),
 +        LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
 +        LintId::of(&loops::WHILE_LET_LOOP),
 +        LintId::of(&loops::WHILE_LET_ON_ITERATOR),
 +        LintId::of(&main_recursion::MAIN_RECURSION),
 +        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
 +        LintId::of(&manual_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_identity::MAP_IDENTITY),
 +        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
 +        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
 +        LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +        LintId::of(&matches::MATCH_AS_REF),
 +        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
 +        LintId::of(&matches::MATCH_OVERLAPPING_ARM),
 +        LintId::of(&matches::MATCH_REF_PATS),
 +        LintId::of(&matches::MATCH_SINGLE_BINDING),
 +        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
 +        LintId::of(&matches::SINGLE_MATCH),
 +        LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
 +        LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
 +        LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +        LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +        LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
 +        LintId::of(&methods::BIND_INSTEAD_OF_MAP),
 +        LintId::of(&methods::CHARS_LAST_CMP),
 +        LintId::of(&methods::CHARS_NEXT_CMP),
 +        LintId::of(&methods::CLONE_DOUBLE_REF),
 +        LintId::of(&methods::CLONE_ON_COPY),
 +        LintId::of(&methods::EXPECT_FUN_CALL),
 +        LintId::of(&methods::FILTER_NEXT),
 +        LintId::of(&methods::FLAT_MAP_IDENTITY),
 +        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
 +        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_NEXT_SLICE),
 +        LintId::of(&methods::ITER_NTH),
 +        LintId::of(&methods::ITER_NTH_ZERO),
 +        LintId::of(&methods::ITER_SKIP_NEXT),
 +        LintId::of(&methods::MANUAL_FILTER_MAP),
 +        LintId::of(&methods::MANUAL_FIND_MAP),
 +        LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
 +        LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
 +        LintId::of(&methods::NEW_RET_NO_SELF),
 +        LintId::of(&methods::OK_EXPECT),
 +        LintId::of(&methods::OPTION_AS_REF_DEREF),
 +        LintId::of(&methods::OPTION_MAP_OR_NONE),
 +        LintId::of(&methods::OR_FUN_CALL),
 +        LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
 +        LintId::of(&methods::SEARCH_IS_SOME),
 +        LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
 +        LintId::of(&methods::SINGLE_CHAR_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::UNINIT_ASSUMED_INIT),
 +        LintId::of(&methods::UNNECESSARY_FILTER_MAP),
 +        LintId::of(&methods::UNNECESSARY_FOLD),
 +        LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
 +        LintId::of(&methods::USELESS_ASREF),
 +        LintId::of(&methods::WRONG_SELF_CONVENTION),
 +        LintId::of(&methods::ZST_OFFSET),
 +        LintId::of(&minmax::MIN_MAX),
 +        LintId::of(&misc::CMP_NAN),
 +        LintId::of(&misc::CMP_OWNED),
 +        LintId::of(&misc::FLOAT_CMP),
 +        LintId::of(&misc::MODULO_ONE),
 +        LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
 +        LintId::of(&misc::TOPLEVEL_REF_ARG),
 +        LintId::of(&misc::ZERO_PTR),
 +        LintId::of(&misc_early::BUILTIN_TYPE_SHADOW),
 +        LintId::of(&misc_early::DOUBLE_NEG),
 +        LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +        LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS),
 +        LintId::of(&misc_early::REDUNDANT_PATTERN),
 +        LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
 +        LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
 +        LintId::of(&mut_key::MUTABLE_KEY_TYPE),
 +        LintId::of(&mut_mutex_lock::MUT_MUTEX_LOCK),
 +        LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
 +        LintId::of(&mutex_atomic::MUTEX_ATOMIC),
 +        LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
 +        LintId::of(&needless_bool::BOOL_COMPARISON),
 +        LintId::of(&needless_bool::NEEDLESS_BOOL),
 +        LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
 +        LintId::of(&needless_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_expressive_names::MANY_SINGLE_CHAR_NAMES),
 +        LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
 +        LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
 +        LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
 +        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +        LintId::of(&precedence::PRECEDENCE),
 +        LintId::of(&ptr::CMP_NULL),
 +        LintId::of(&ptr::MUT_FROM_REF),
 +        LintId::of(&ptr::PTR_ARG),
 +        LintId::of(&ptr_eq::PTR_EQ),
 +        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +        LintId::of(&question_mark::QUESTION_MARK),
 +        LintId::of(&ranges::MANUAL_RANGE_CONTAINS),
 +        LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
 +        LintId::of(&ranges::REVERSED_EMPTY_RANGES),
 +        LintId::of(&redundant_clone::REDUNDANT_CLONE),
 +        LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
 +        LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
 +        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
 +        LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +        LintId::of(&reference::DEREF_ADDROF),
 +        LintId::of(&reference::REF_IN_DEREF),
 +        LintId::of(&regex::INVALID_REGEX),
 +        LintId::of(&regex::TRIVIAL_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(&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(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +        LintId::of(&swap::ALMOST_SWAPPED),
 +        LintId::of(&swap::MANUAL_SWAP),
 +        LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +        LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
 +        LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
 +        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
 +        LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
 +        LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
 +        LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR),
 +        LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT),
 +        LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR),
 +        LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
 +        LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +        LintId::of(&transmute::WRONG_TRANSMUTE),
 +        LintId::of(&transmuting_null::TRANSMUTING_NULL),
 +        LintId::of(&try_err::TRY_ERR),
 +        LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
 +        LintId::of(&types::BORROWED_BOX),
 +        LintId::of(&types::BOX_VEC),
 +        LintId::of(&types::CAST_REF_TO_MUT),
 +        LintId::of(&types::CHAR_LIT_AS_U8),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +        LintId::of(&types::REDUNDANT_ALLOCATION),
 +        LintId::of(&types::TYPE_COMPLEXITY),
 +        LintId::of(&types::UNIT_ARG),
 +        LintId::of(&types::UNIT_CMP),
 +        LintId::of(&types::UNNECESSARY_CAST),
 +        LintId::of(&types::VEC_BOX),
 +        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +        LintId::of(&unicode::INVISIBLE_CHARACTERS),
 +        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +        LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
 +        LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +        LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
 +        LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +        LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
 +        LintId::of(&unused_unit::UNUSED_UNIT),
 +        LintId::of(&unwrap::PANICKING_UNWRAP),
 +        LintId::of(&unwrap::UNNECESSARY_UNWRAP),
 +        LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +        LintId::of(&useless_conversion::USELESS_CONVERSION),
 +        LintId::of(&vec::USELESS_VEC),
 +        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
 +        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +        LintId::of(&write::PRINTLN_EMPTY_STRING),
 +        LintId::of(&write::PRINT_LITERAL),
 +        LintId::of(&write::PRINT_WITH_NEWLINE),
 +        LintId::of(&write::WRITELN_EMPTY_STRING),
 +        LintId::of(&write::WRITE_LITERAL),
 +        LintId::of(&write::WRITE_WITH_NEWLINE),
 +        LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +    ]);
 +
 +    store.register_group(true, "clippy::style", Some("clippy_style"), vec![
 +        LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +        LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
 +        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +        LintId::of(&blacklisted_name::BLACKLISTED_NAME),
 +        LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_ELSE_IF),
 +        LintId::of(&collapsible_if::COLLAPSIBLE_IF),
 +        LintId::of(&collapsible_match::COLLAPSIBLE_MATCH),
 +        LintId::of(&comparison_chain::COMPARISON_CHAIN),
 +        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
 +        LintId::of(&doc::MISSING_SAFETY_DOC),
 +        LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
 +        LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
 +        LintId::of(&enum_variants::MODULE_INCEPTION),
 +        LintId::of(&eq_op::OP_REF),
 +        LintId::of(&eta_reduction::REDUNDANT_CLOSURE),
 +        LintId::of(&float_literal::EXCESSIVE_PRECISION),
 +        LintId::of(&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(&functions::DOUBLE_MUST_USE),
 +        LintId::of(&functions::MUST_USE_UNIT),
 +        LintId::of(&functions::RESULT_UNIT_ERR),
 +        LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
 +        LintId::of(&inherent_to_string::INHERENT_TO_STRING),
 +        LintId::of(&len_zero::COMPARISON_TO_EMPTY),
 +        LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
 +        LintId::of(&len_zero::LEN_ZERO),
 +        LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +        LintId::of(&literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +        LintId::of(&loops::EMPTY_LOOP),
 +        LintId::of(&loops::FOR_KV_MAP),
 +        LintId::of(&loops::NEEDLESS_RANGE_LOOP),
 +        LintId::of(&loops::SAME_ITEM_PUSH),
 +        LintId::of(&loops::WHILE_LET_ON_ITERATOR),
 +        LintId::of(&main_recursion::MAIN_RECURSION),
 +        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
 +        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +        LintId::of(&map_clone::MAP_CLONE),
 +        LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
 +        LintId::of(&matches::MATCH_OVERLAPPING_ARM),
 +        LintId::of(&matches::MATCH_REF_PATS),
 +        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
 +        LintId::of(&matches::SINGLE_MATCH),
 +        LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +        LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +        LintId::of(&methods::CHARS_LAST_CMP),
 +        LintId::of(&methods::CHARS_NEXT_CMP),
 +        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
 +        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::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(&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(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
 +        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(&regex::TRIVIAL_REGEX),
 +        LintId::of(&returns::LET_AND_RETURN),
 +        LintId::of(&returns::NEEDLESS_RETURN),
 +        LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +        LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
 +        LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +        LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
 +        LintId::of(&try_err::TRY_ERR),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST),
 +        LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +        LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +        LintId::of(&unused_unit::UNUSED_UNIT),
 +        LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +        LintId::of(&write::PRINTLN_EMPTY_STRING),
 +        LintId::of(&write::PRINT_LITERAL),
 +        LintId::of(&write::PRINT_WITH_NEWLINE),
 +        LintId::of(&write::WRITELN_EMPTY_STRING),
 +        LintId::of(&write::WRITE_LITERAL),
 +        LintId::of(&write::WRITE_WITH_NEWLINE),
 +    ]);
 +
 +    store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
 +        LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
 +        LintId::of(&attrs::DEPRECATED_CFG_ATTR),
 +        LintId::of(&booleans::NONMINIMAL_BOOL),
 +        LintId::of(&double_comparison::DOUBLE_COMPARISONS),
 +        LintId::of(&double_parens::DOUBLE_PARENS),
 +        LintId::of(&duration_subsec::DURATION_SUBSEC),
 +        LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +        LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +        LintId::of(&explicit_write::EXPLICIT_WRITE),
 +        LintId::of(&format::USELESS_FORMAT),
 +        LintId::of(&functions::TOO_MANY_ARGUMENTS),
 +        LintId::of(&get_last_with_len::GET_LAST_WITH_LEN),
 +        LintId::of(&identity_op::IDENTITY_OP),
 +        LintId::of(&int_plus_one::INT_PLUS_ONE),
 +        LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
 +        LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
 +        LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
 +        LintId::of(&loops::MUT_RANGE_BOUND),
 +        LintId::of(&loops::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_identity::MAP_IDENTITY),
 +        LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
 +        LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
 +        LintId::of(&matches::MATCH_AS_REF),
 +        LintId::of(&matches::MATCH_SINGLE_BINDING),
 +        LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
 +        LintId::of(&methods::BIND_INSTEAD_OF_MAP),
 +        LintId::of(&methods::CLONE_ON_COPY),
 +        LintId::of(&methods::FILTER_NEXT),
 +        LintId::of(&methods::FLAT_MAP_IDENTITY),
 +        LintId::of(&methods::INSPECT_FOR_EACH),
 +        LintId::of(&methods::MANUAL_FILTER_MAP),
 +        LintId::of(&methods::MANUAL_FIND_MAP),
 +        LintId::of(&methods::OPTION_AS_REF_DEREF),
 +        LintId::of(&methods::SEARCH_IS_SOME),
 +        LintId::of(&methods::SKIP_WHILE_NEXT),
 +        LintId::of(&methods::SUSPICIOUS_MAP),
 +        LintId::of(&methods::UNNECESSARY_FILTER_MAP),
 +        LintId::of(&methods::USELESS_ASREF),
 +        LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
 +        LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
 +        LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
 +        LintId::of(&needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
 +        LintId::of(&needless_bool::BOOL_COMPARISON),
 +        LintId::of(&needless_bool::NEEDLESS_BOOL),
 +        LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
 +        LintId::of(&needless_question_mark::NEEDLESS_QUESTION_MARK),
 +        LintId::of(&needless_update::NEEDLESS_UPDATE),
 +        LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
 +        LintId::of(&no_effect::NO_EFFECT),
 +        LintId::of(&no_effect::UNNECESSARY_OPERATION),
 +        LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
 +        LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +        LintId::of(&precedence::PRECEDENCE),
 +        LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +        LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
 +        LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
 +        LintId::of(&redundant_slicing::REDUNDANT_SLICING),
 +        LintId::of(&reference::DEREF_ADDROF),
 +        LintId::of(&reference::REF_IN_DEREF),
 +        LintId::of(&repeat_once::REPEAT_ONCE),
 +        LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
 +        LintId::of(&swap::MANUAL_SWAP),
 +        LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
 +        LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
 +        LintId::of(&transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
 +        LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR),
 +        LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR),
 +        LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT),
 +        LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR),
 +        LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
 +        LintId::of(&types::BORROWED_BOX),
 +        LintId::of(&types::CHAR_LIT_AS_U8),
 +        LintId::of(&types::TYPE_COMPLEXITY),
 +        LintId::of(&types::UNIT_ARG),
 +        LintId::of(&types::UNNECESSARY_CAST),
 +        LintId::of(&types::VEC_BOX),
 +        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +        LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
 +        LintId::of(&unwrap::UNNECESSARY_UNWRAP),
 +        LintId::of(&useless_conversion::USELESS_CONVERSION),
 +        LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +    ]);
 +
 +    store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
 +        LintId::of(&approx_const::APPROX_CONSTANT),
 +        LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC),
 +        LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
 +        LintId::of(&attrs::DEPRECATED_SEMVER),
 +        LintId::of(&attrs::MISMATCHED_TARGET_OS),
 +        LintId::of(&attrs::USELESS_ATTRIBUTE),
 +        LintId::of(&bit_mask::BAD_BIT_MASK),
 +        LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
 +        LintId::of(&booleans::LOGIC_BUG),
 +        LintId::of(&copies::IFS_SAME_COND),
 +        LintId::of(&copies::IF_SAME_THEN_ELSE),
 +        LintId::of(&derive::DERIVE_HASH_XOR_EQ),
 +        LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +        LintId::of(&drop_forget_ref::DROP_COPY),
 +        LintId::of(&drop_forget_ref::DROP_REF),
 +        LintId::of(&drop_forget_ref::FORGET_COPY),
 +        LintId::of(&drop_forget_ref::FORGET_REF),
 +        LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +        LintId::of(&eq_op::EQ_OP),
 +        LintId::of(&erasing_op::ERASING_OP),
 +        LintId::of(&float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +        LintId::of(&formatting::POSSIBLE_MISSING_COMMA),
 +        LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +        LintId::of(&if_let_mutex::IF_LET_MUTEX),
 +        LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +        LintId::of(&infinite_iter::INFINITE_ITER),
 +        LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
 +        LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +        LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
 +        LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +        LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES),
 +        LintId::of(&loops::ITER_NEXT_LOOP),
 +        LintId::of(&loops::NEVER_LOOP),
 +        LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
 +        LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
 +        LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
 +        LintId::of(&methods::CLONE_DOUBLE_REF),
 +        LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
 +        LintId::of(&methods::UNINIT_ASSUMED_INIT),
 +        LintId::of(&methods::ZST_OFFSET),
 +        LintId::of(&minmax::MIN_MAX),
 +        LintId::of(&misc::CMP_NAN),
 +        LintId::of(&misc::FLOAT_CMP),
 +        LintId::of(&misc::MODULO_ONE),
 +        LintId::of(&mut_key::MUTABLE_KEY_TYPE),
 +        LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
 +        LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
 +        LintId::of(&ptr::MUT_FROM_REF),
 +        LintId::of(&ranges::REVERSED_EMPTY_RANGES),
 +        LintId::of(&regex::INVALID_REGEX),
 +        LintId::of(&self_assignment::SELF_ASSIGNMENT),
 +        LintId::of(&serde_api::SERDE_API_MISUSE),
 +        LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +        LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +        LintId::of(&swap::ALMOST_SWAPPED),
 +        LintId::of(&to_string_in_display::TO_STRING_IN_DISPLAY),
 +        LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +        LintId::of(&transmute::WRONG_TRANSMUTE),
 +        LintId::of(&transmuting_null::TRANSMUTING_NULL),
 +        LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
 +        LintId::of(&types::CAST_REF_TO_MUT),
 +        LintId::of(&types::UNIT_CMP),
 +        LintId::of(&undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +        LintId::of(&unicode::INVISIBLE_CHARACTERS),
 +        LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +        LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
 +        LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +        LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
 +        LintId::of(&unwrap::PANICKING_UNWRAP),
 +        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +    ]);
 +
 +    store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
 +        LintId::of(&bytecount::NAIVE_BYTECOUNT),
 +        LintId::of(&entry::MAP_ENTRY),
 +        LintId::of(&escape::BOXED_LOCAL),
 +        LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
 +        LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
 +        LintId::of(&loops::MANUAL_MEMCPY),
 +        LintId::of(&loops::NEEDLESS_COLLECT),
 +        LintId::of(&methods::EXPECT_FUN_CALL),
 +        LintId::of(&methods::ITER_NTH),
 +        LintId::of(&methods::OR_FUN_CALL),
 +        LintId::of(&methods::SINGLE_CHAR_PATTERN),
 +        LintId::of(&misc::CMP_OWNED),
 +        LintId::of(&mutex_atomic::MUTEX_ATOMIC),
 +        LintId::of(&redundant_clone::REDUNDANT_CLONE),
 +        LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
 +        LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
 +        LintId::of(&types::BOX_VEC),
 +        LintId::of(&types::REDUNDANT_ALLOCATION),
 +        LintId::of(&vec::USELESS_VEC),
 +        LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
 +    ]);
 +
 +    store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
 +        LintId::of(&cargo_common_metadata::CARGO_COMMON_METADATA),
 +        LintId::of(&multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
 +        LintId::of(&wildcard_dependencies::WILDCARD_DEPENDENCIES),
 +    ]);
 +
 +    store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
 +        LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
 +        LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
 +        LintId::of(&disallowed_method::DISALLOWED_METHOD),
 +        LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
 +        LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
 +        LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
 +        LintId::of(&future_not_send::FUTURE_NOT_SEND),
 +        LintId::of(&let_if_seq::USELESS_LET_IF_SEQ),
 +        LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN),
 +        LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
 +        LintId::of(&mutex_atomic::MUTEX_INTEGER),
 +        LintId::of(&needless_borrow::NEEDLESS_BORROW),
 +        LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
 +        LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
 +        LintId::of(&strings::STRING_LIT_AS_BYTES),
 +        LintId::of(&transmute::USELESS_TRANSMUTE),
 +        LintId::of(&use_self::USE_SELF),
 +    ]);
 +}
 +
 +#[rustfmt::skip]
 +fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_removed(
 +        "should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "reverse_range_loop",
 +        "this lint is now included in reversed_empty_ranges",
 +    );
 +}
 +
 +/// Register renamed lints.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
 +    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
 +    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
 +    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
 +    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
 +    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
 +    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
 +    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 +    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 +}
 +
 +// 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 5f62d2d13165c181fbe4d6245a74df482c7f6ead,0000000000000000000000000000000000000000..ba7b9bd04248d3d2713fa597f421e80e2e00c0ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,1975 -1,0 +1,1985 @@@
-             _ => return Some((a.range(), b.range())),
 +use crate::consts::{constant, miri_to_const, Constant};
 +use crate::utils::sugg::Sugg;
 +use crate::utils::usage::is_unused;
 +use crate::utils::{
 +    expr_block, get_arg_name, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of,
 +    is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg,
 +    peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt,
 +    snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 +};
 +use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
 +use if_chain::if_chain;
 +use rustc_ast::ast::LitKind;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_errors::Applicability;
 +use rustc_hir::def::CtorKind;
 +use rustc_hir::{
 +    Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat,
 +    PatKind, QPath, RangeEnd,
 +};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, Ty, TyS};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::{sym, Symbol};
 +use std::cmp::Ordering;
 +use std::collections::hash_map::Entry;
 +use std::collections::Bound;
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for matches with a single arm where an `if let`
 +    /// will usually suffice.
 +    ///
 +    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # fn bar(stool: &str) {}
 +    /// # let x = Some("abc");
 +    /// // Bad
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => (),
 +    /// }
 +    ///
 +    /// // Good
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH,
 +    style,
 +    "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for matches with two arms where an `if let else` will
 +    /// usually suffice.
 +    ///
 +    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// **Known problems:** Personal style preferences may differ.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// Using `match`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => bar(&other_ref),
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `if let` with `else`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// } else {
 +    ///     bar(&other_ref);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH_ELSE,
 +    pedantic,
 +    "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for matches where all arms match a reference,
 +    /// suggesting to remove the reference and deref the matched expression
 +    /// instead. It also checks for `if let &foo = bar` blocks.
 +    ///
 +    /// **Why is this bad?** It just makes the code less readable. That reference
 +    /// destructuring adds nothing to the code.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// match x {
 +    ///     &A(ref y) => foo(y),
 +    ///     &B => bar(),
 +    ///     _ => frob(&x),
 +    /// }
 +    ///
 +    /// // Good
 +    /// match *x {
 +    ///     A(ref y) => foo(y),
 +    ///     B => bar(),
 +    ///     _ => frob(x),
 +    /// }
 +    /// ```
 +    pub MATCH_REF_PATS,
 +    style,
 +    "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for matches where match expression is a `bool`. It
 +    /// suggests to replace the expression with an `if...else` block.
 +    ///
 +    /// **Why is this bad?** It makes the code less readable.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// match condition {
 +    ///     true => foo(),
 +    ///     false => bar(),
 +    /// }
 +    /// ```
 +    /// Use if/else instead:
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// if condition {
 +    ///     foo();
 +    /// } else {
 +    ///     bar();
 +    /// }
 +    /// ```
 +    pub MATCH_BOOL,
 +    pedantic,
 +    "a `match` on a boolean expression instead of an `if..else` block"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for overlapping match arms.
 +    ///
 +    /// **Why is this bad?** It is likely to be an error and if not, makes the code
 +    /// less obvious.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = 5;
 +    /// match x {
 +    ///     1...10 => println!("1 ... 10"),
 +    ///     5...15 => println!("5 ... 15"),
 +    ///     _ => (),
 +    /// }
 +    /// ```
 +    pub MATCH_OVERLAPPING_ARM,
 +    style,
 +    "a `match` with overlapping arms"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for arm which matches all errors with `Err(_)`
 +    /// and take drastic actions like `panic!`.
 +    ///
 +    /// **Why is this bad?** It is generally a bad practice, similar to
 +    /// catching all exceptions in java with `catch(Exception)`
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x: Result<i32, &str> = Ok(3);
 +    /// match x {
 +    ///     Ok(_) => println!("ok"),
 +    ///     Err(_) => panic!("err"),
 +    /// }
 +    /// ```
 +    pub MATCH_WILD_ERR_ARM,
 +    pedantic,
 +    "a `match` with `Err(_)` arm and take drastic actions"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for match which is used to add a reference to an
 +    /// `Option` value.
 +    ///
 +    /// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x: Option<()> = None;
 +    ///
 +    /// // Bad
 +    /// let r: Option<&()> = match x {
 +    ///     None => None,
 +    ///     Some(ref v) => Some(v),
 +    /// };
 +    ///
 +    /// // Good
 +    /// let r: Option<&()> = x.as_ref();
 +    /// ```
 +    pub MATCH_AS_REF,
 +    complexity,
 +    "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for wildcard enum matches using `_`.
 +    ///
 +    /// **Why is this bad?** New enum variants added by library updates can be missed.
 +    ///
 +    /// **Known problems:** Suggested replacements may be incorrect if guards exhaustively cover some
 +    /// variants, and also may not use correct path to enum if it's not present in the current scope.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # enum Foo { A(usize), B(usize) }
 +    /// # let x = Foo::B(1);
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     Foo::B(_) => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_ENUM_MATCH_ARM,
 +    restriction,
 +    "a wildcard enum match arm using `_`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for wildcard enum matches for a single variant.
 +    ///
 +    /// **Why is this bad?** New enum variants added by library updates can be missed.
 +    ///
 +    /// **Known problems:** Suggested replacements may not use correct path to enum
 +    /// if it's not present in the current scope.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// # enum Foo { A, B, C }
 +    /// # let x = Foo::B;
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     Foo::C => {},
 +    /// }
 +    /// ```
 +    pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    pedantic,
 +    "a wildcard enum match for a single variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm.
 +    ///
 +    /// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway.
 +    /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// // Bad
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     "bar" | _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_IN_OR_PATTERNS,
 +    complexity,
 +    "a wildcard pattern used with others patterns in same match arm"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for matches being used to destructure a single-variant enum
 +    /// or tuple struct where a `let` will suffice.
 +    ///
 +    /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    ///
 +    /// let data = match wrapper {
 +    ///     Wrapper::Data(i) => i,
 +    /// };
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    /// let Wrapper::Data(data) = wrapper;
 +    /// ```
 +    pub INFALLIBLE_DESTRUCTURING_MATCH,
 +    style,
 +    "a `match` statement with a single infallible arm instead of a `let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for useless match that binds to only one value.
 +    ///
 +    /// **Why is this bad?** Readability and needless complexity.
 +    ///
 +    /// **Known problems:**  Suggested replacements may be incorrect when `match`
 +    /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let a = 1;
 +    /// # let b = 2;
 +    ///
 +    /// // Bad
 +    /// match (a, b) {
 +    ///     (c, d) => {
 +    ///         // useless match
 +    ///     }
 +    /// }
 +    ///
 +    /// // Good
 +    /// let (c, d) = (a, b);
 +    /// ```
 +    pub MATCH_SINGLE_BINDING,
 +    complexity,
 +    "a match with a single binding instead of using `let` statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
 +    ///
 +    /// **Why is this bad?** Correctness and readability. It's like having a wildcard pattern after
 +    /// matching all enum variants explicitly.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # struct A { a: i32 }
 +    /// let a = A { a: 5 };
 +    ///
 +    /// // Bad
 +    /// match a {
 +    ///     A { a: 5, .. } => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match a {
 +    ///     A { a: 5 } => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    restriction,
 +    "a match on a struct that binds all fields but still uses the wildcard pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Lint for redundant pattern matching over `Result`, `Option`,
 +    /// `std::task::Poll` or `std::net::IpAddr`
 +    ///
 +    /// **Why is this bad?** It's more concise and clear to just use the proper
 +    /// utility function
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if let Ok(_) = Ok::<i32, i32>(42) {}
 +    /// if let Err(_) = Err::<i32, i32>(42) {}
 +    /// if let None = None::<()> {}
 +    /// if let Some(_) = Some(42) {}
 +    /// if let Poll::Pending = Poll::Pending::<()> {}
 +    /// if let Poll::Ready(_) = Poll::Ready(42) {}
 +    /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
 +    /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
 +    /// match Ok::<i32, i32>(42) {
 +    ///     Ok(_) => true,
 +    ///     Err(_) => false,
 +    /// };
 +    /// ```
 +    ///
 +    /// The more idiomatic use would be:
 +    ///
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if Ok::<i32, i32>(42).is_ok() {}
 +    /// if Err::<i32, i32>(42).is_err() {}
 +    /// if None::<()>.is_none() {}
 +    /// if Some(42).is_some() {}
 +    /// if Poll::Pending::<()>.is_pending() {}
 +    /// if Poll::Ready(42).is_ready() {}
 +    /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
 +    /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
 +    /// Ok::<i32, i32>(42).is_ok();
 +    /// ```
 +    pub REDUNDANT_PATTERN_MATCHING,
 +    style,
 +    "use the proper utility function avoiding an `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `match`  or `if let` expressions producing a
 +    /// `bool` that could be written using `matches!`
 +    ///
 +    /// **Why is this bad?** Readability and needless complexity.
 +    ///
 +    /// **Known problems:** This lint falsely triggers, if there are arms with
 +    /// `cfg` attributes that remove an arm evaluating to `false`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// let x = Some(5);
 +    ///
 +    /// // Bad
 +    /// let a = match x {
 +    ///     Some(0) => true,
 +    ///     _ => false,
 +    /// };
 +    ///
 +    /// let a = if let Some(0) = x {
 +    ///     true
 +    /// } else {
 +    ///     false
 +    /// };
 +    ///
 +    /// // Good
 +    /// let a = matches!(x, Some(0));
 +    /// ```
 +    pub MATCH_LIKE_MATCHES_MACRO,
 +    style,
 +    "a match that could be written with the matches! macro"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for `match` with identical arm bodies.
 +    ///
 +    /// **Why is this bad?** This is probably a copy & paste error. If arm bodies
 +    /// are the same on purpose, you can factor them
 +    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
 +    ///
 +    /// **Known problems:** False positive possible with order dependent `match`
 +    /// (see issue
 +    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => bar(), // <= oops
 +    /// }
 +    /// ```
 +    ///
 +    /// This should probably be
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => baz(), // <= fixed
 +    /// }
 +    /// ```
 +    ///
 +    /// or if the original code was not a typo:
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar | Baz => bar(), // <= shows the intent better
 +    ///     Quz => quz(),
 +    /// }
 +    /// ```
 +    pub MATCH_SAME_ARMS,
 +    pedantic,
 +    "`match` with identical arm bodies"
 +}
 +
 +#[derive(Default)]
 +pub struct Matches {
 +    msrv: Option<RustcVersion>,
 +    infallible_destructuring_match_linted: bool,
 +}
 +
 +impl Matches {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            msrv,
 +            ..Matches::default()
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(Matches => [
 +    SINGLE_MATCH,
 +    MATCH_REF_PATS,
 +    MATCH_BOOL,
 +    SINGLE_MATCH_ELSE,
 +    MATCH_OVERLAPPING_ARM,
 +    MATCH_WILD_ERR_ARM,
 +    MATCH_AS_REF,
 +    WILDCARD_ENUM_MATCH_ARM,
 +    MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    WILDCARD_IN_OR_PATTERNS,
 +    MATCH_SINGLE_BINDING,
 +    INFALLIBLE_DESTRUCTURING_MATCH,
 +    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    REDUNDANT_PATTERN_MATCHING,
 +    MATCH_LIKE_MATCHES_MACRO,
 +    MATCH_SAME_ARMS,
 +]);
 +
 +const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0);
 +
 +impl<'tcx> LateLintPass<'tcx> for Matches {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
 +            return;
 +        }
 +
 +        redundant_pattern_match::check(cx, expr);
 +
 +        if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) {
 +            if !check_match_like_matches(cx, expr) {
 +                lint_match_arms(cx, expr);
 +            }
 +        } else {
 +            lint_match_arms(cx, expr);
 +        }
 +
 +        if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
 +            check_single_match(cx, ex, arms, expr);
 +            check_match_bool(cx, ex, arms, expr);
 +            check_overlapping_arms(cx, ex, arms);
 +            check_wild_err_arm(cx, ex, arms);
 +            check_wild_enum_match(cx, ex, arms);
 +            check_match_as_ref(cx, ex, arms, expr);
 +            check_wild_in_or_pats(cx, arms);
 +
 +            if self.infallible_destructuring_match_linted {
 +                self.infallible_destructuring_match_linted = false;
 +            } else {
 +                check_match_single_binding(cx, ex, arms, expr);
 +            }
 +        }
 +        if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
 +            check_match_ref_pats(cx, ex, arms, expr);
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), local.span);
 +            if !in_macro(local.span);
 +            if let Some(ref expr) = local.init;
 +            if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind;
 +            if arms.len() == 1 && arms[0].guard.is_none();
 +            if let PatKind::TupleStruct(
 +                QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind;
 +            if args.len() == 1;
 +            if let Some(arg) = get_arg_name(&args[0]);
 +            let body = remove_blocks(&arms[0].body);
 +            if match_var(body, arg);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                self.infallible_destructuring_match_linted = true;
 +                span_lint_and_sugg(
 +                    cx,
 +                    INFALLIBLE_DESTRUCTURING_MATCH,
 +                    local.span,
 +                    "you seem to be trying to use `match` to destructure a single infallible pattern. \
 +                    Consider using `let`",
 +                    "try this",
 +                    format!(
 +                        "let {}({}) = {};",
 +                        snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, target.span, "..", &mut applicability),
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), pat.span);
 +            if !in_macro(pat.span);
 +            if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind;
 +            if let Some(def_id) = path.res.opt_def_id();
 +            let ty = cx.tcx.type_of(def_id);
 +            if let ty::Adt(def, _) = ty.kind();
 +            if def.is_struct() || def.is_union();
 +            if fields.len() == def.non_enum_variant().fields.len();
 +
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +                    pat.span,
 +                    "unnecessary use of `..` pattern in struct binding. All fields were already bound",
 +                    None,
 +                    "consider removing `..` from this binding",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[rustfmt::skip]
 +fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        if in_macro(expr.span) {
 +            // Don't lint match expressions present in
 +            // macro_rules! block
 +            return;
 +        }
 +        if let PatKind::Or(..) = arms[0].pat.kind {
 +            // don't lint for or patterns for now, this makes
 +            // the lint noisy in unnecessary situations
 +            return;
 +        }
 +        let els = arms[1].body;
 +        let els = if is_unit_expr(remove_blocks(els)) {
 +            None
 +        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
 +            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
 +                // single statement/expr "else" block, don't lint
 +                return;
 +            }
 +            // block with 2+ statements or 1 expr and 1+ statement
 +            Some(els)
 +        } else {
 +            // not a block, don't lint
 +            return;
 +        };
 +
 +        let ty = cx.typeck_results().expr_ty(ex);
 +        if *ty.kind() != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
 +            check_single_match_single_pattern(cx, ex, arms, expr, els);
 +            check_single_match_opt_like(cx, ex, arms, expr, ty, els);
 +        }
 +    }
 +}
 +
 +fn check_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    if is_wild(&arms[1].pat) {
 +        report_single_match_single_pattern(cx, ex, arms, expr, els);
 +    }
 +}
 +
 +fn report_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
 +    let els_str = els.map_or(String::new(), |els| {
 +        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
 +    });
 +
 +    let (msg, sugg) = if_chain! {
 +        let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
 +        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
 +        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
 +        if let Some(trait_id) = cx.tcx.lang_items().structural_peq_trait();
 +        if ty.is_integral() || ty.is_char() || ty.is_str() || implements_trait(cx, ty, trait_id, &[]);
 +        then {
 +            // scrutinee derives PartialEq and the pattern is a constant.
 +            let pat_ref_count = match pat.kind {
 +                // string literals are already a reference.
 +                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
 +                _ => pat_ref_count,
 +            };
 +            // References are only implicitly added to the pattern, so no overflow here.
 +            // e.g. will work: match &Some(_) { Some(_) => () }
 +            // will not: match Some(_) { &Some(_) => () }
 +            let ref_count_diff = ty_ref_count - pat_ref_count;
 +
 +            // Try to remove address of expressions first.
 +            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
 +            let ref_count_diff = ref_count_diff - removed;
 +
 +            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
 +            let sugg = format!(
 +                "if {} == {}{} {}{}",
 +                snippet(cx, ex.span, ".."),
 +                // PartialEq for different reference counts may not exist.
 +                "&".repeat(ref_count_diff),
 +                snippet(cx, arms[0].pat.span, ".."),
 +                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        } else {
 +            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
 +            let sugg = format!(
 +                "if let {} = {} {}{}",
 +                snippet(cx, arms[0].pat.span, ".."),
 +                snippet(cx, ex.span, ".."),
 +                expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        }
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        lint,
 +        expr.span,
 +        msg,
 +        "try this",
 +        sugg,
 +        Applicability::HasPlaceholders,
 +    );
 +}
 +
 +fn check_single_match_opt_like(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    ty: Ty<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    // list of candidate `Enum`s we know will never get any more members
 +    let candidates = &[
 +        (&paths::COW, "Borrowed"),
 +        (&paths::COW, "Cow::Borrowed"),
 +        (&paths::COW, "Cow::Owned"),
 +        (&paths::COW, "Owned"),
 +        (&paths::OPTION, "None"),
 +        (&paths::RESULT, "Err"),
 +        (&paths::RESULT, "Ok"),
 +    ];
 +
 +    let path = match arms[1].pat.kind {
 +        PatKind::TupleStruct(ref path, ref inner, _) => {
 +            // Contains any non wildcard patterns (e.g., `Err(err)`)?
 +            if !inner.iter().all(is_wild) {
 +                return;
 +            }
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
 +        PatKind::Path(ref path) => {
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        _ => return,
 +    };
 +
 +    for &(ty_path, pat_path) in candidates {
 +        if path == *pat_path && match_type(cx, ty, ty_path) {
 +            report_single_match_single_pattern(cx, ex, arms, expr, els);
 +        }
 +    }
 +}
 +
 +fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    // Type of expression is `bool`.
 +    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
 +        span_lint_and_then(
 +            cx,
 +            MATCH_BOOL,
 +            expr.span,
 +            "you seem to be trying to match on a boolean expression",
 +            move |diag| {
 +                if arms.len() == 2 {
 +                    // no guards
 +                    let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pat.kind {
 +                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
 +                            match lit.node {
 +                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
 +                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
 +                                _ => None,
 +                            }
 +                        } else {
 +                            None
 +                        }
 +                    } else {
 +                        None
 +                    };
 +
 +                    if let Some((true_expr, false_expr)) = exprs {
 +                        let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
 +                            (false, false) => Some(format!(
 +                                "if {} {} else {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
 +                                expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (false, true) => Some(format!(
 +                                "if {} {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (true, false) => {
 +                                let test = Sugg::hir(cx, ex, "..");
 +                                Some(format!(
 +                                    "if {} {}",
 +                                    !test,
 +                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                                ))
 +                            },
 +                            (true, true) => None,
 +                        };
 +
 +                        if let Some(sugg) = sugg {
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "consider using an `if`/`else` expression",
 +                                sugg,
 +                                Applicability::HasPlaceholders,
 +                            );
 +                        }
 +                    }
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
 +    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
 +        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
 +        let type_ranges = type_ranges(&ranges);
 +        if !type_ranges.is_empty() {
 +            if let Some((start, end)) = overlapping(&type_ranges) {
 +                span_lint_and_note(
 +                    cx,
 +                    MATCH_OVERLAPPING_ARM,
 +                    start.span,
 +                    "some ranges overlap",
 +                    Some(end.span),
 +                    "overlaps with this",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 +    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
 +    if is_type_diagnostic_item(cx, ex_ty, sym::result_type) {
 +        for arm in arms {
 +            if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
 +                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
 +                if path_str == "Err" {
 +                    let mut matching_wild = inner.iter().any(is_wild);
 +                    let mut ident_bind_name = String::from("_");
 +                    if !matching_wild {
 +                        // Looking for unused bindings (i.e.: `_e`)
 +                        inner.iter().for_each(|pat| {
 +                            if let PatKind::Binding(.., ident, None) = &pat.kind {
 +                                if ident.as_str().starts_with('_') && is_unused(ident, arm.body) {
 +                                    ident_bind_name = (&ident.name.as_str()).to_string();
 +                                    matching_wild = true;
 +                                }
 +                            }
 +                        });
 +                    }
 +                    if_chain! {
 +                        if matching_wild;
 +                        if let ExprKind::Block(ref block, _) = arm.body.kind;
 +                        if is_panic_block(block);
 +                        then {
 +                            // `Err(_)` or `Err(_e)` arm with `panic!` found
 +                            span_lint_and_note(cx,
 +                                MATCH_WILD_ERR_ARM,
 +                                arm.pat.span,
 +                                &format!("`Err({})` matches all errors", &ident_bind_name),
 +                                None,
 +                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 +    let ty = cx.typeck_results().expr_ty(ex);
 +    if !ty.is_enum() {
 +        // If there isn't a nice closed set of possible values that can be conveniently enumerated,
 +        // don't complain about not enumerating the mall.
 +        return;
 +    }
 +
 +    // First pass - check for violation, but don't do much book-keeping because this is hopefully
 +    // the uncommon case, and the book-keeping is slightly expensive.
 +    let mut wildcard_span = None;
 +    let mut wildcard_ident = None;
 +    for arm in arms {
 +        if let PatKind::Wild = arm.pat.kind {
 +            wildcard_span = Some(arm.pat.span);
 +        } else if let PatKind::Binding(_, _, ident, None) = arm.pat.kind {
 +            wildcard_span = Some(arm.pat.span);
 +            wildcard_ident = Some(ident);
 +        }
 +    }
 +
 +    if let Some(wildcard_span) = wildcard_span {
 +        // Accumulate the variants which should be put in place of the wildcard because they're not
 +        // already covered.
 +
 +        let mut missing_variants = vec![];
 +        if let ty::Adt(def, _) = ty.kind() {
 +            for variant in &def.variants {
 +                missing_variants.push(variant);
 +            }
 +        }
 +
 +        for arm in arms {
 +            if arm.guard.is_some() {
 +                // Guards mean that this case probably isn't exhaustively covered. Technically
 +                // this is incorrect, as we should really check whether each variant is exhaustively
 +                // covered by the set of guards that cover it, but that's really hard to do.
 +                continue;
 +            }
 +            if let PatKind::Path(ref path) = arm.pat.kind {
 +                if let QPath::Resolved(_, p) = path {
 +                    missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
 +                }
 +            } else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind {
 +                // Some simple checks for exhaustive patterns.
 +                // There is a room for improvements to detect more cases,
 +                // but it can be more expensive to do so.
 +                let is_pattern_exhaustive =
 +                    |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None));
 +                if patterns.iter().all(is_pattern_exhaustive) {
 +                    missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
 +                }
 +            }
 +        }
 +
 +        let mut suggestion: Vec<String> = missing_variants
 +            .iter()
 +            .map(|v| {
 +                let suffix = match v.ctor_kind {
 +                    CtorKind::Fn => "(..)",
 +                    CtorKind::Const | CtorKind::Fictive => "",
 +                };
 +                let ident_str = if let Some(ident) = wildcard_ident {
 +                    format!("{} @ ", ident.name)
 +                } else {
 +                    String::new()
 +                };
 +                // This path assumes that the enum type is imported into scope.
 +                format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix)
 +            })
 +            .collect();
 +
 +        if suggestion.is_empty() {
 +            return;
 +        }
 +
 +        let mut message = "wildcard match will miss any future added variants";
 +
 +        if let ty::Adt(def, _) = ty.kind() {
 +            if def.is_variant_list_non_exhaustive() {
 +                message = "match on non-exhaustive enum doesn't explicitly match all known variants";
 +                suggestion.push(String::from("_"));
 +            }
 +        }
 +
 +        if suggestion.len() == 1 {
 +            // No need to check for non-exhaustive enum as in that case len would be greater than 1
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +                wildcard_span,
 +                message,
 +                "try this",
 +                suggestion[0].clone(),
 +                Applicability::MaybeIncorrect,
 +            )
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            WILDCARD_ENUM_MATCH_ARM,
 +            wildcard_span,
 +            message,
 +            "try this",
 +            suggestion.join(" | "),
 +            Applicability::MaybeIncorrect,
 +        )
 +    }
 +}
 +
 +// If the block contains only a `panic!` macro (as expression or statement)
 +fn is_panic_block(block: &Block<'_>) -> bool {
 +    match (&block.expr, block.stmts.len(), block.stmts.first()) {
 +        (&Some(ref exp), 0, _) => {
 +            is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none()
 +        },
 +        (&None, 1, Some(stmt)) => {
 +            is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
 +        },
 +        _ => false,
 +    }
 +}
 +
 +fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if has_only_ref_pats(arms) {
 +        let mut suggs = Vec::with_capacity(arms.len() + 1);
 +        let (title, msg) = if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = ex.kind {
 +            let span = ex.span.source_callsite();
 +            suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
 +            (
 +                "you don't need to add `&` to both the expression and the patterns",
 +                "try",
 +            )
 +        } else {
 +            let span = ex.span.source_callsite();
 +            suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
 +            (
 +                "you don't need to add `&` to all patterns",
 +                "instead of prefixing all patterns with `&`, you can dereference the expression",
 +            )
 +        };
 +
 +        suggs.extend(arms.iter().filter_map(|a| {
 +            if let PatKind::Ref(ref refp, _) = a.pat.kind {
 +                Some((a.pat.span, snippet(cx, refp.span, "..").to_string()))
 +            } else {
 +                None
 +            }
 +        }));
 +
 +        span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
 +            if !expr.span.from_expansion() {
 +                multispan_sugg(diag, msg, suggs);
 +            }
 +        });
 +    }
 +}
 +
 +fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) {
 +            is_ref_some_arm(&arms[1])
 +        } else if is_none_arm(&arms[1]) {
 +            is_ref_some_arm(&arms[0])
 +        } else {
 +            None
 +        };
 +        if let Some(rb) = arm_ref {
 +            let suggestion = if rb == BindingAnnotation::Ref {
 +                "as_ref"
 +            } else {
 +                "as_mut"
 +            };
 +
 +            let output_ty = cx.typeck_results().expr_ty(expr);
 +            let input_ty = cx.typeck_results().expr_ty(ex);
 +
 +            let cast = if_chain! {
 +                if let ty::Adt(_, substs) = input_ty.kind();
 +                let input_ty = substs.type_at(0);
 +                if let ty::Adt(_, substs) = output_ty.kind();
 +                let output_ty = substs.type_at(0);
 +                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
 +                if input_ty != output_ty;
 +                then {
 +                    ".map(|x| x as _)"
 +                } else {
 +                    ""
 +                }
 +            };
 +
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_AS_REF,
 +                expr.span,
 +                &format!("use `{}()` instead", suggestion),
 +                "try this",
 +                format!(
 +                    "{}.{}(){}",
 +                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
 +                    suggestion,
 +                    cast,
 +                ),
 +                applicability,
 +            )
 +        }
 +    }
 +}
 +
 +fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
 +    for arm in arms {
 +        if let PatKind::Or(ref fields) = arm.pat.kind {
 +            // look for multiple fields in this arm that contains at least one Wild pattern
 +            if fields.len() > 1 && fields.iter().any(is_wild) {
 +                span_lint_and_help(
 +                    cx,
 +                    WILDCARD_IN_OR_PATTERNS,
 +                    arm.pat.span,
 +                    "wildcard pattern covers any other pattern as it will match anyway.",
 +                    None,
 +                    "Consider handling `_` separately.",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
 +fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +    if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
 +        match match_source {
 +            MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
 +            MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
 +            _ => false,
 +        }
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Lint a `match` or desugared `if let` for replacement by `matches!`
 +fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) -> bool {
 +    if_chain! {
 +        if arms.len() >= 2;
 +        if cx.typeck_results().expr_ty(expr).is_bool();
 +        if let Some((b1_arm, b0_arms)) = arms.split_last();
 +        if let Some(b0) = find_bool_lit(&b0_arms[0].body.kind, desugared);
 +        if let Some(b1) = find_bool_lit(&b1_arm.body.kind, desugared);
 +        if is_wild(&b1_arm.pat);
 +        if b0 != b1;
 +        let if_guard = &b0_arms[0].guard;
 +        if if_guard.is_none() || b0_arms.len() == 1;
 +        if b0_arms[0].attrs.is_empty();
 +        if b0_arms[1..].iter()
 +            .all(|arm| {
 +                find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) &&
 +                arm.guard.is_none() && arm.attrs.is_empty()
 +            });
 +        then {
 +            // The suggestion may be incorrect, because some arms can have `cfg` attributes
 +            // evaluated into `false` and so such arms will be stripped before.
 +            let mut applicability = Applicability::MaybeIncorrect;
 +            let pat = {
 +                use itertools::Itertools as _;
 +                b0_arms.iter()
 +                    .map(|arm| snippet_with_applicability(cx, arm.pat.span, "..", &mut applicability))
 +                    .join(" | ")
 +            };
 +            let pat_and_guard = if let Some(Guard::If(g)) = if_guard {
 +                format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
 +            } else {
 +                pat
 +            };
 +
 +            // strip potential borrows (#6503), but only if the type is a reference
 +            let mut ex_new = ex;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
 +                if let ty::Ref(..) = cx.typeck_results().expr_ty(&ex_inner).kind() {
 +                    ex_new = ex_inner;
 +                }
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_LIKE_MATCHES_MACRO,
 +                expr.span,
 +                &format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
 +                "try this",
 +                format!(
 +                    "{}matches!({}, {})",
 +                    if b0 { "" } else { "!" },
 +                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
 +                    pat_and_guard,
 +                ),
 +                applicability,
 +            );
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Extract a `bool` or `{ bool }`
 +fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
 +    match ex {
 +        ExprKind::Lit(Spanned {
 +            node: LitKind::Bool(b), ..
 +        }) => Some(*b),
 +        ExprKind::Block(
 +            rustc_hir::Block {
 +                stmts: &[],
 +                expr: Some(exp),
 +                ..
 +            },
 +            _,
 +        ) if desugared => {
 +            if let ExprKind::Lit(Spanned {
 +                node: LitKind::Bool(b), ..
 +            }) = exp.kind
 +            {
 +                Some(b)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
 +        return;
 +    }
 +
 +    // HACK:
 +    // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
 +    // to prevent false positives as there is currently no better way to detect if code was excluded by
 +    // a macro. See PR #6435
 +    if_chain! {
 +        if let Some(match_snippet) = snippet_opt(cx, expr.span);
 +        if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
 +        if let Some(ex_snippet) = snippet_opt(cx, ex.span);
 +        let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
 +        if rest_snippet.contains("=>");
 +        then {
 +            // The code it self contains another thick arrow "=>"
 +            // -> Either another arm or a comment
 +            return;
 +        }
 +    }
 +
 +    let matched_vars = ex.span;
 +    let bind_names = arms[0].pat.span;
 +    let match_body = remove_blocks(&arms[0].body);
 +    let mut snippet_body = if match_body.span.from_expansion() {
 +        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
 +    } else {
 +        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
 +    };
 +
 +    // Do we need to add ';' to suggestion ?
 +    match match_body.kind {
 +        ExprKind::Block(block, _) => {
 +            // macro + expr_ty(body) == ()
 +            if block.span.from_expansion() && cx.typeck_results().expr_ty(&match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +        _ => {
 +            // expr_ty(body) == ()
 +            if cx.typeck_results().expr_ty(&match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +    }
 +
 +    let mut applicability = Applicability::MaybeIncorrect;
 +    match arms[0].pat.kind {
 +        PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
 +            // If this match is in a local (`let`) stmt
 +            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
 +                (
 +                    parent_let_node.span,
 +                    format!(
 +                        "let {} = {};\n{}let {} = {};",
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
 +                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
 +                        snippet_body
 +                    ),
 +                )
 +            } else {
 +                // If we are in closure, we need curly braces around suggestion
 +                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
 +                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
 +                if let Some(parent_expr) = get_parent_expr(cx, expr) {
 +                    if let ExprKind::Closure(..) = parent_expr.kind {
 +                        cbrace_end = format!("\n{}}}", indent);
 +                        // Fix body indent due to the closure
 +                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
 +                        cbrace_start = format!("{{\n{}", indent);
 +                    }
 +                };
 +                (
 +                    expr.span,
 +                    format!(
 +                        "{}let {} = {};\n{}{}{}",
 +                        cbrace_start,
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        indent,
 +                        snippet_body,
 +                        cbrace_end
 +                    ),
 +                )
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_SINGLE_BINDING,
 +                target_span,
 +                "this match could be written as a `let` statement",
 +                "consider using `let` statement",
 +                sugg,
 +                applicability,
 +            );
 +        },
 +        PatKind::Wild => {
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_SINGLE_BINDING,
 +                expr.span,
 +                "this match could be replaced by its body itself",
 +                "consider using the match body instead",
 +                snippet_body,
 +                Applicability::MachineApplicable,
 +            );
 +        },
 +        _ => (),
 +    }
 +}
 +
 +/// Returns true if the `ex` match expression is in a local (`let`) statement
 +fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
 +    if_chain! {
 +        let map = &cx.tcx.hir();
 +        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
 +        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
 +        then {
 +            return Some(parent_let_expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets all arms that are unbounded `PatRange`s.
 +fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
 +    arms.iter()
 +        .flat_map(|arm| {
 +            if let Arm {
 +                ref pat, guard: None, ..
 +            } = *arm
 +            {
 +                if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
 +                    let lhs = match lhs {
 +                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
 +                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
 +                    };
 +                    let rhs = match rhs {
 +                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
 +                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
 +                    };
 +                    let rhs = match range_end {
 +                        RangeEnd::Included => Bound::Included(rhs),
 +                        RangeEnd::Excluded => Bound::Excluded(rhs),
 +                    };
 +                    return Some(SpannedRange {
 +                        span: pat.span,
 +                        node: (lhs, rhs),
 +                    });
 +                }
 +
 +                if let PatKind::Lit(ref value) = pat.kind {
 +                    let value = constant(cx, cx.typeck_results(), value)?.0;
 +                    return Some(SpannedRange {
 +                        span: pat.span,
 +                        node: (value.clone(), Bound::Included(value)),
 +                    });
 +                }
 +            }
 +            None
 +        })
 +        .collect()
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct SpannedRange<T> {
 +    pub span: Span,
 +    pub node: (T, Bound<T>),
 +}
 +
 +type TypedRanges = Vec<SpannedRange<u128>>;
 +
 +/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
 +/// and other types than
 +/// `Uint` and `Int` probably don't make sense.
 +fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
 +    ranges
 +        .iter()
 +        .filter_map(|range| match range.node {
 +            (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Included(end)),
 +            }),
 +            (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Excluded(end)),
 +            }),
 +            (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
 +                span: range.span,
 +                node: (start, Bound::Unbounded),
 +            }),
 +            _ => None,
 +        })
 +        .collect()
 +}
 +
 +fn is_unit_expr(expr: &Expr<'_>) -> bool {
 +    match expr.kind {
 +        ExprKind::Tup(ref v) if v.is_empty() => true,
 +        ExprKind::Block(ref b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
 +        _ => false,
 +    }
 +}
 +
 +// Checks if arm has the form `None => None`
 +fn is_none_arm(arm: &Arm<'_>) -> bool {
 +    matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE))
 +}
 +
 +// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 +fn is_ref_some_arm(arm: &Arm<'_>) -> Option<BindingAnnotation> {
 +    if_chain! {
 +        if let PatKind::TupleStruct(ref path, ref pats, _) = arm.pat.kind;
 +        if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME);
 +        if let PatKind::Binding(rb, .., ident, _) = pats[0].kind;
 +        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
 +        if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind;
 +        if let ExprKind::Path(ref some_path) = e.kind;
 +        if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1;
 +        if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind;
 +        if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
 +        then {
 +            return Some(rb)
 +        }
 +    }
 +    None
 +}
 +
 +fn has_only_ref_pats(arms: &[Arm<'_>]) -> bool {
 +    let mapped = arms
 +        .iter()
 +        .map(|a| {
 +            match a.pat.kind {
 +                PatKind::Ref(..) => Some(true), // &-patterns
 +                PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
 +                _ => None,                      // any other pattern is not fine
 +            }
 +        })
 +        .collect::<Option<Vec<bool>>>();
 +    // look for Some(v) where there's at least one true element
 +    mapped.map_or(false, |v| v.iter().any(|el| *el))
 +}
 +
 +pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
 +where
 +    T: Copy + Ord,
 +{
 +    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +    enum Kind<'a, T> {
 +        Start(T, &'a SpannedRange<T>),
 +        End(Bound<T>, &'a SpannedRange<T>),
 +    }
 +
 +    impl<'a, T: Copy> Kind<'a, T> {
 +        fn range(&self) -> &'a SpannedRange<T> {
 +            match *self {
 +                Kind::Start(_, r) | Kind::End(_, r) => r,
 +            }
 +        }
 +
 +        fn value(self) -> Bound<T> {
 +            match self {
 +                Kind::Start(t, _) => Bound::Included(t),
 +                Kind::End(t, _) => t,
 +            }
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> {
 +        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 +            Some(self.cmp(other))
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
 +        fn cmp(&self, other: &Self) -> Ordering {
 +            match (self.value(), other.value()) {
 +                (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
 +                // Range patterns cannot be unbounded (yet)
 +                (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
 +                (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Greater,
 +                    other => other,
 +                },
 +                (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Less,
 +                    other => other,
 +                },
 +            }
 +        }
 +    }
 +
 +    let mut values = Vec::with_capacity(2 * ranges.len());
 +
 +    for r in ranges {
 +        values.push(Kind::Start(r.node.0, r));
 +        values.push(Kind::End(r.node.1, r));
 +    }
 +
 +    values.sort();
 +
 +    for (a, b) in values.iter().zip(values.iter().skip(1)) {
 +        match (a, b) {
 +            (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
 +                if ra.node != rb.node {
 +                    return Some((ra, rb));
 +                }
 +            },
 +            (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
++            _ => {
++                // skip if the range `a` is completely included into the range `b`
++                if let Ordering::Equal | Ordering::Less = a.cmp(&b) {
++                    let kind_a = Kind::End(a.range().node.1, a.range());
++                    let kind_b = Kind::End(b.range().node.1, b.range());
++                    if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
++                        return None;
++                    }
++                }
++                return Some((a.range(), b.range()));
++            },
 +        }
 +    }
 +
 +    None
 +}
 +
 +mod redundant_pattern_match {
 +    use super::REDUNDANT_PATTERN_MATCHING;
 +    use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
 +    use if_chain::if_chain;
 +    use rustc_ast::ast::LitKind;
 +    use rustc_errors::Applicability;
 +    use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
 +    use rustc_lint::LateContext;
 +    use rustc_span::sym;
 +
 +    pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
 +            match match_source {
 +                MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
 +                MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
 +                MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
 +                _ => {},
 +            }
 +        }
 +    }
 +
 +    fn find_sugg_for_if_let<'tcx>(
 +        cx: &LateContext<'tcx>,
 +        expr: &'tcx Expr<'_>,
 +        op: &Expr<'_>,
 +        arms: &[Arm<'_>],
 +        keyword: &'static str,
 +    ) {
 +        let good_method = match arms[0].pat.kind {
 +            PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
 +                if let PatKind::Wild = patterns[0].kind {
 +                    if match_qpath(path, &paths::RESULT_OK) {
 +                        "is_ok()"
 +                    } else if match_qpath(path, &paths::RESULT_ERR) {
 +                        "is_err()"
 +                    } else if match_qpath(path, &paths::OPTION_SOME) {
 +                        "is_some()"
 +                    } else if match_qpath(path, &paths::POLL_READY) {
 +                        "is_ready()"
 +                    } else if match_qpath(path, &paths::IPADDR_V4) {
 +                        "is_ipv4()"
 +                    } else if match_qpath(path, &paths::IPADDR_V6) {
 +                        "is_ipv6()"
 +                    } else {
 +                        return;
 +                    }
 +                } else {
 +                    return;
 +                }
 +            },
 +            PatKind::Path(ref path) => {
 +                if match_qpath(path, &paths::OPTION_NONE) {
 +                    "is_none()"
 +                } else if match_qpath(path, &paths::POLL_PENDING) {
 +                    "is_pending()"
 +                } else {
 +                    return;
 +                }
 +            },
 +            _ => return,
 +        };
 +
 +        // check that `while_let_on_iterator` lint does not trigger
 +        if_chain! {
 +            if keyword == "while";
 +            if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
 +            if method_path.ident.name == sym::next;
 +            if match_trait_method(cx, op, &paths::ITERATOR);
 +            then {
 +                return;
 +            }
 +        }
 +
 +        let result_expr = match &op.kind {
 +            ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +            _ => op,
 +        };
 +        span_lint_and_then(
 +            cx,
 +            REDUNDANT_PATTERN_MATCHING,
 +            arms[0].pat.span,
 +            &format!("redundant pattern matching, consider using `{}`", good_method),
 +            |diag| {
 +                // while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +                let expr_span = expr.span;
 +
 +                // while let ... = ... { ... }
 +                //                 ^^^
 +                let op_span = result_expr.span.source_callsite();
 +
 +                // while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^
 +                let span = expr_span.until(op_span.shrink_to_hi());
 +                diag.span_suggestion(
 +                    span,
 +                    "try this",
 +                    format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
 +                    Applicability::MachineApplicable, // snippet
 +                );
 +            },
 +        );
 +    }
 +
 +    fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
 +        if arms.len() == 2 {
 +            let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 +
 +            let found_good_method = match node_pair {
 +                (
 +                    PatKind::TupleStruct(ref path_left, ref patterns_left, _),
 +                    PatKind::TupleStruct(ref path_right, ref patterns_right, _),
 +                ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
 +                    if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
 +                        find_good_method_for_match(
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::RESULT_OK,
 +                            &paths::RESULT_ERR,
 +                            "is_ok()",
 +                            "is_err()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::IPADDR_V4,
 +                                &paths::IPADDR_V6,
 +                                "is_ipv4()",
 +                                "is_ipv6()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
 +                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
 +                    if patterns.len() == 1 =>
 +                {
 +                    if let PatKind::Wild = patterns[0].kind {
 +                        find_good_method_for_match(
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::OPTION_SOME,
 +                            &paths::OPTION_NONE,
 +                            "is_some()",
 +                            "is_none()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::POLL_READY,
 +                                &paths::POLL_PENDING,
 +                                "is_ready()",
 +                                "is_pending()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                _ => None,
 +            };
 +
 +            if let Some(good_method) = found_good_method {
 +                let span = expr.span.to(op.span);
 +                let result_expr = match &op.kind {
 +                    ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +                    _ => op,
 +                };
 +                span_lint_and_then(
 +                    cx,
 +                    REDUNDANT_PATTERN_MATCHING,
 +                    expr.span,
 +                    &format!("redundant pattern matching, consider using `{}`", good_method),
 +                    |diag| {
 +                        diag.span_suggestion(
 +                            span,
 +                            "try this",
 +                            format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
 +                            Applicability::MaybeIncorrect, // snippet
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +    }
 +
 +    fn find_good_method_for_match<'a>(
 +        arms: &[Arm<'_>],
 +        path_left: &QPath<'_>,
 +        path_right: &QPath<'_>,
 +        expected_left: &[&str],
 +        expected_right: &[&str],
 +        should_be_left: &'a str,
 +        should_be_right: &'a str,
 +    ) -> Option<&'a str> {
 +        let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
 +            (&(*arms[0].body).kind, &(*arms[1].body).kind)
 +        } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
 +            (&(*arms[1].body).kind, &(*arms[0].body).kind)
 +        } else {
 +            return None;
 +        };
 +
 +        match body_node_pair {
 +            (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
 +                (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
 +                (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
 +                _ => None,
 +            },
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[test]
 +fn test_overlapping() {
 +    use rustc_span::source_map::DUMMY_SP;
 +
 +    let sp = |s, e| SpannedRange {
 +        span: DUMMY_SP,
 +        node: (s, e),
 +    };
 +
 +    assert_eq!(None, overlapping::<u8>(&[]));
 +    assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
 +    assert_eq!(
 +        None,
 +        overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        None,
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(10, Bound::Included(11))
 +        ],)
 +    );
 +    assert_eq!(
 +        Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
 +        overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(6, Bound::Included(11))
 +        ],)
 +    );
 +}
 +
 +/// Implementation of `MATCH_SAME_ARMS`.
 +fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +    fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol, Ty<'tcx>>) -> bool {
 +        lhs.len() == rhs.len()
 +            && lhs
 +                .iter()
 +                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty)))
 +    }
 +
 +    if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
 +        let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
 +            let mut h = SpanlessHash::new(cx);
 +            h.hash_expr(&arm.body);
 +            h.finish()
 +        };
 +
 +        let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
 +            let min_index = usize::min(lindex, rindex);
 +            let max_index = usize::max(lindex, rindex);
 +
 +            // Arms with a guard are ignored, those can’t always be merged together
 +            // This is also the case for arms in-between each there is an arm with a guard
 +            (min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
 +                SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
 +                // all patterns should have the same bindings
 +                same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat))
 +        };
 +
 +        let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
 +        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
 +            span_lint_and_then(
 +                cx,
 +                MATCH_SAME_ARMS,
 +                j.body.span,
 +                "this `match` has identical arm bodies",
 +                |diag| {
 +                    diag.span_note(i.body.span, "same as this");
 +
 +                    // Note: this does not use `span_suggestion` on purpose:
 +                    // there is no clean way
 +                    // to remove the other arm. Building a span and suggest to replace it to ""
 +                    // makes an even more confusing error message. Also in order not to make up a
 +                    // span for the whole pattern, the suggestion is only shown when there is only
 +                    // one pattern. The user should know about `|` if they are already using it…
 +
 +                    let lhs = snippet(cx, i.pat.span, "<pat1>");
 +                    let rhs = snippet(cx, j.pat.span, "<pat2>");
 +
 +                    if let PatKind::Wild = j.pat.kind {
 +                        // if the last arm is _, then i could be integrated into _
 +                        // note that i.pat cannot be _, because that would mean that we're
 +                        // hiding all the subsequent arms, and rust won't compile
 +                        diag.span_note(
 +                            i.body.span,
 +                            &format!(
 +                                "`{}` has the same arm body as the `_` wildcard, consider removing it",
 +                                lhs
 +                            ),
 +                        );
 +                    } else {
 +                        diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
 +                    }
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +/// Returns the list of bindings in a pattern.
 +fn bindings<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> FxHashMap<Symbol, Ty<'tcx>> {
 +    fn bindings_impl<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
 +        match pat.kind {
 +            PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
 +            PatKind::TupleStruct(_, pats, _) => {
 +                for pat in pats {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Binding(.., ident, ref as_pat) => {
 +                if let Entry::Vacant(v) = map.entry(ident.name) {
 +                    v.insert(cx.typeck_results().pat_ty(pat));
 +                }
 +                if let Some(ref as_pat) = *as_pat {
 +                    bindings_impl(cx, as_pat, map);
 +                }
 +            },
 +            PatKind::Or(fields) | PatKind::Tuple(fields, _) => {
 +                for pat in fields {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Struct(_, fields, _) => {
 +                for pat in fields {
 +                    bindings_impl(cx, &pat.pat, map);
 +                }
 +            },
 +            PatKind::Slice(lhs, ref mid, rhs) => {
 +                for pat in lhs {
 +                    bindings_impl(cx, pat, map);
 +                }
 +                if let Some(ref mid) = *mid {
 +                    bindings_impl(cx, mid, map);
 +                }
 +                for pat in rhs {
 +                    bindings_impl(cx, pat, map);
 +                }
 +            },
 +            PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (),
 +        }
 +    }
 +
 +    let mut result = FxHashMap::default();
 +    bindings_impl(cx, pat, &mut result);
 +    result
 +}
index 69492e84e4ac58c44c79316000d830451cd37b28,0000000000000000000000000000000000000000..642326469725fce4194e31ea222a794ef92134c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,581 -1,0 +1,576 @@@
-         }
 +//! Utilities for manipulating and extracting information from `rustc_ast::ast`.
 +//!
 +//! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s.
 +
 +#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
 +
 +use crate::utils::{both, over};
 +use rustc_ast::ptr::P;
 +use rustc_ast::{self as ast, *};
 +use rustc_span::symbol::Ident;
 +use std::mem;
 +
 +pub mod ident_iter;
 +pub use ident_iter::IdentIter;
 +
 +pub fn is_useless_with_eq_exprs(kind: BinOpKind) -> bool {
 +    use BinOpKind::*;
 +    matches!(
 +        kind,
 +        Sub | Div | Eq | Lt | Le | Gt | Ge | Ne | And | Or | BitXor | BitAnd | BitOr
 +    )
 +}
 +
 +/// Checks if each element in the first slice is contained within the latter as per `eq_fn`.
 +pub fn unordered_over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
 +    left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r)))
 +}
 +
 +pub fn eq_id(l: Ident, r: Ident) -> bool {
 +    l.name == r.name
 +}
 +
 +pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
 +    use PatKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_pat(l, r),
 +        (_, Paren(r)) => eq_pat(l, r),
 +        (Wild, Wild) | (Rest, Rest) => true,
 +        (Lit(l), Lit(r)) => eq_expr(l, r),
 +        (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)),
 +        (Range(lf, lt, le), Range(rf, rt, re)) => {
 +            eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node)
 +        },
 +        (Box(l), Box(r))
 +        | (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
 +        | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
 +        (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
 +        (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
 +            lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
 +        },
 +        (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool {
 +    match (l, r) {
 +        (RangeEnd::Excluded, RangeEnd::Excluded) => true,
 +        (RangeEnd::Included(l), RangeEnd::Included(r)) => {
 +            matches!(l, RangeSyntax::DotDotEq) == matches!(r, RangeSyntax::DotDotEq)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_field_pat(l: &FieldPat, r: &FieldPat) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && eq_pat(&l.pat, &r.pat)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
 +    l.position == r.position && eq_ty(&l.ty, &r.ty)
 +}
 +
 +pub fn eq_path(l: &Path, r: &Path) -> bool {
 +    over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
 +}
 +
 +pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
 +    eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r))
 +}
 +
 +pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
 +    match (l, r) {
 +        (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => {
 +            over(&l.args, &r.args, |l, r| eq_angle_arg(l, r))
 +        },
 +        (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => {
 +            over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output)
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool {
 +    match (l, r) {
 +        (AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r),
 +        (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
 +    match (l, r) {
 +        (GenericArg::Lifetime(l), GenericArg::Lifetime(r)) => eq_id(l.ident, r.ident),
 +        (GenericArg::Type(l), GenericArg::Type(r)) => eq_ty(l, r),
 +        (GenericArg::Const(l), GenericArg::Const(r)) => eq_expr(&l.value, &r.value),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
 +    both(l, r, |l, r| eq_expr(l, r))
 +}
 +
 +pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
 +    match (l, r) {
 +        (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb),
 +        (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true,
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
 +    use ExprKind::*;
 +    if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
 +        return false;
 +    }
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_expr(l, r),
 +        (_, Paren(r)) => eq_expr(l, r),
 +        (Err, Err) => true,
 +        (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
 +        (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
 +        (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
 +        (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
 +        (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
 +        (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
 +        (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
 +        (Lit(l), Lit(r)) => l.kind == r.kind,
 +        (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
 +        (Let(lp, le), Let(rp, re)) => eq_pat(lp, rp) && eq_expr(le, re),
 +        (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
 +        (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
 +        (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
 +            eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
 +        },
 +        (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt),
 +        (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
 +        (TryBlock(l), TryBlock(r)) => eq_block(l, r),
 +        (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
 +        (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
 +        (Continue(ll), Continue(rl)) => eq_label(ll, rl),
 +        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
 +        (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
 +        (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
 +        (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)),
 +        (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
 +            lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
 +        },
 +        (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
 +        (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
 +        (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        (Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
 +            eq_path(lp, rp) && eq_struct_rest(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_field(l: &Field, r: &Field) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && eq_expr(&l.expr, &r.expr)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && eq_pat(&l.pat, &r.pat)
 +        && eq_expr(&l.body, &r.body)
 +        && eq_expr_opt(&l.guard, &r.guard)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
 +    both(l, r, |l, r| eq_id(l.ident, r.ident))
 +}
 +
 +pub fn eq_block(l: &Block, r: &Block) -> bool {
 +    l.rules == r.rules && over(&l.stmts, &r.stmts, |l, r| eq_stmt(l, r))
 +}
 +
 +pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
 +    use StmtKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Local(l), Local(r)) => {
 +            eq_pat(&l.pat, &r.pat)
 +                && both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
 +                && eq_expr_opt(&l.init, &r.init)
 +                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        },
 +        (Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
 +        (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
 +        (Empty, Empty) => true,
 +        (MacCall(l), MacCall(r)) => {
 +            l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool {
 +    eq_id(l.ident, r.ident)
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && eq_kind(&l.kind, &r.kind)
 +}
 +
 +pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
 +    use ItemKind::*;
 +    match (l, r) {
 +        (ExternCrate(l), ExternCrate(r)) => l == r,
 +        (Use(l), Use(r)) => eq_use_tree(l, r),
 +        (Static(lt, lm, le), Static(rt, rm, re)) => {
 +            lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re)
 +        }
 +        (Const(ld, lt, le), Const(rd, rt, re)) => {
 +            eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re)
 +        }
 +        (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_fn_sig(lf, rf)
 +                && eq_generics(lg, rg)
 +                && both(lb, rb, |l, r| eq_block(l, r))
 +        }
 +        (Mod(l), Mod(r)) => {
 +            l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind))
 +        }
 +        (ForeignMod(l), ForeignMod(r)) => {
 +            both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
 +                && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
-         }
++        },
 +        (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (Enum(le, lg), Enum(re, rg)) => {
 +            over(&le.variants, &re.variants, |l, r| eq_variant(l, r)) && eq_generics(lg, rg)
 +        },
 +        (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
 +            eq_variant_data(lv, rv) && eq_generics(lg, rg)
-         (Const(ld, lt, le), Const(rd, rt, re)) => {
-             eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re)
-         }
++        },
 +        (Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => {
 +            la == ra
 +                && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
 +        },
 +        (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, |l, r| eq_generic_bound(l, r)),
 +        (
 +            Impl(box ImplKind {
 +                unsafety: lu,
 +                polarity: lp,
 +                defaultness: ld,
 +                constness: lc,
 +                generics: lg,
 +                of_trait: lot,
 +                self_ty: lst,
 +                items: li,
 +            }),
 +            Impl(box ImplKind {
 +                unsafety: ru,
 +                polarity: rp,
 +                defaultness: rd,
 +                constness: rc,
 +                generics: rg,
 +                of_trait: rot,
 +                self_ty: rst,
 +                items: ri,
 +            }),
 +        ) => {
 +            matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
 +                && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
 +                && eq_defaultness(*ld, *rd)
 +                && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
 +                && eq_generics(lg, rg)
 +                && both(lot, rot, |l, r| eq_path(&l.path, &r.path))
 +                && eq_ty(lst, rst)
 +                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_mac_args(&l.body, &r.body),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
 +    use ForeignItemKind::*;
 +    match (l, r) {
 +        (Static(lt, lm, le), Static(rt, rm, re)) => {
 +            lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re)
 +        }
 +        (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_fn_sig(lf, rf)
 +                && eq_generics(lg, rg)
 +                && both(lb, rb, |l, r| eq_block(l, r))
 +        }
 +        (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
 +    use AssocItemKind::*;
 +    match (l, r) {
-             eq_defaultness(*ld, *rd)
-                 && eq_fn_sig(lf, rf)
-                 && eq_generics(lg, rg)
-                 && both(lb, rb, |l, r| eq_block(l, r))
-         }
++        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
 +        (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
++            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
++        },
 +        (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
 +            eq_defaultness(*ld, *rd)
 +                && eq_generics(lg, rg)
 +                && over(lb, rb, |l, r| eq_generic_bound(l, r))
 +                && both(lt, rt, |l, r| eq_ty(l, r))
 +        },
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && eq_id(l.ident, r.ident)
 +        && eq_variant_data(&l.data, &r.data)
 +        && both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value))
 +}
 +
 +pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
 +    use VariantData::*;
 +    match (l, r) {
 +        (Unit(_), Unit(_)) => true,
 +        (Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, |l, r| eq_struct_field(l, r)),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_struct_field(l: &StructField, r: &StructField) -> bool {
 +    l.is_placeholder == r.is_placeholder
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        && eq_vis(&l.vis, &r.vis)
 +        && both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
 +        && eq_ty(&l.ty, &r.ty)
 +}
 +
 +pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
 +    eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header)
 +}
 +
 +pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
 +    matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
 +        && l.asyncness.is_async() == r.asyncness.is_async()
 +        && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
 +        && eq_ext(&l.ext, &r.ext)
 +}
 +
 +pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
 +    over(&l.params, &r.params, |l, r| eq_generic_param(l, r))
 +        && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
 +            eq_where_predicate(l, r)
 +        })
 +}
 +
 +pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
 +    use WherePredicate::*;
 +    match (l, r) {
 +        (BoundPredicate(l), BoundPredicate(r)) => {
 +            over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
 +                eq_generic_param(l, r)
 +            }) && eq_ty(&l.bounded_ty, &r.bounded_ty)
 +                && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        },
 +        (RegionPredicate(l), RegionPredicate(r)) => {
 +            eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        },
 +        (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool {
 +    eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind)
 +}
 +
 +pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
 +    use UseTreeKind::*;
 +    match (l, r) {
 +        (Glob, Glob) => true,
 +        (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)),
 +        (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_anon_const(l: &AnonConst, r: &AnonConst) -> bool {
 +    eq_expr(&l.value, &r.value)
 +}
 +
 +pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
 +    matches!(
 +        (l, r),
 +        (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))
 +    )
 +}
 +
 +pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
 +    use VisibilityKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true,
 +        (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
 +    eq_fn_ret_ty(&l.output, &r.output)
 +        && over(&l.inputs, &r.inputs, |l, r| {
 +            l.is_placeholder == r.is_placeholder
 +                && eq_pat(&l.pat, &r.pat)
 +                && eq_ty(&l.ty, &r.ty)
 +                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +        })
 +}
 +
 +pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool {
 +    match (l, r) {
 +        (FnRetTy::Default(_), FnRetTy::Default(_)) => true,
 +        (FnRetTy::Ty(l), FnRetTy::Ty(r)) => eq_ty(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
 +    use TyKind::*;
 +    match (&l.kind, &r.kind) {
 +        (Paren(l), _) => eq_ty(l, r),
 +        (_, Paren(r)) => eq_ty(l, r),
 +        (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true,
 +        (Slice(l), Slice(r)) => eq_ty(l, r),
 +        (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
 +        (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
 +        (Rptr(ll, l), Rptr(rl, r)) => {
 +            both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
 +        },
 +        (BareFn(l), BareFn(r)) => {
 +            l.unsafety == r.unsafety
 +                && eq_ext(&l.ext, &r.ext)
 +                && over(&l.generic_params, &r.generic_params, |l, r| eq_generic_param(l, r))
 +                && eq_fn_decl(&l.decl, &r.decl)
 +        },
 +        (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
 +        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
 +        (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, |l, r| eq_generic_bound(l, r)),
 +        (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, |l, r| eq_generic_bound(l, r)),
 +        (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
 +        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_ext(l: &Extern, r: &Extern) -> bool {
 +    use Extern::*;
 +    match (l, r) {
 +        (None, None) | (Implicit, Implicit) => true,
 +        (Explicit(l), Explicit(r)) => eq_str_lit(l, r),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_str_lit(l: &StrLit, r: &StrLit) -> bool {
 +    l.style == r.style && l.symbol == r.symbol && l.suffix == r.suffix
 +}
 +
 +pub fn eq_poly_ref_trait(l: &PolyTraitRef, r: &PolyTraitRef) -> bool {
 +    eq_path(&l.trait_ref.path, &r.trait_ref.path)
 +        && over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
 +            eq_generic_param(l, r)
 +        })
 +}
 +
 +pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
 +    use GenericParamKind::*;
 +    l.is_placeholder == r.is_placeholder
 +        && eq_id(l.ident, r.ident)
 +        && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
 +        && match (&l.kind, &r.kind) {
 +            (Lifetime, Lifetime) => true,
 +            (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
 +            (
 +                Const {
 +                    ty: lt,
 +                    kw_span: _,
 +                    default: ld,
 +                },
 +                Const {
 +                    ty: rt,
 +                    kw_span: _,
 +                    default: rd,
 +                },
 +            ) => eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
 +            _ => false,
 +        }
 +        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
 +}
 +
 +pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
 +    use GenericBound::*;
 +    match (l, r) {
 +        (Trait(ptr1, tbm1), Trait(ptr2, tbm2)) => tbm1 == tbm2 && eq_poly_ref_trait(ptr1, ptr2),
 +        (Outlives(l), Outlives(r)) => eq_id(l.ident, r.ident),
 +        _ => false,
 +    }
 +}
 +
 +pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
 +    use AssocTyConstraintKind::*;
 +    eq_id(l.ident, r.ident)
 +        && match (&l.kind, &r.kind) {
 +            (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
 +            (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, |l, r| eq_generic_bound(l, r)),
 +            _ => false,
 +        }
 +}
 +
 +pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool {
 +    eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args)
 +}
 +
 +pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
 +    use AttrKind::*;
 +    l.style == r.style
 +        && match (&l.kind, &r.kind) {
 +            (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
 +            (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
 +            _ => false,
 +        }
 +}
 +
 +pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
 +    use MacArgs::*;
 +    match (l, r) {
 +        (Empty, Empty) => true,
 +        (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts),
 +        (Eq(_, lt), Eq(_, rt)) => lt.kind == rt.kind,
 +        _ => false,
 +    }
 +}
index 6caa04f651fae8366910e39749fca8742e53f904,0000000000000000000000000000000000000000..269be217c2d875bf3db450a39940705666154459
mode 100644,000000..100644
--- /dev/null
@@@ -1,226 -1,0 +1,226 @@@
-     span: Span,
 +//! Clippy wrappers around rustc's diagnostic functions.
 +
 +use rustc_errors::{Applicability, DiagnosticBuilder};
 +use rustc_hir::HirId;
 +use rustc_lint::{LateContext, Lint, LintContext};
 +use rustc_span::source_map::{MultiSpan, Span};
 +use std::env;
 +
 +fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
 +    if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
 +        diag.help(&format!(
 +            "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
 +            &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
 +                // extract just major + minor version and ignore patch versions
 +                format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
 +            }),
 +            lint.name_lower().replacen("clippy::", "", 1)
 +        ));
 +    }
 +}
 +
 +/// Emit a basic lint message with a `msg` and a `span`.
 +///
 +/// This is the most primitive of our lint emission methods and can
 +/// be a good way to get a new lint started.
 +///
 +/// Usually it's nicer to provide more context for lint messages.
 +/// Be sure the output is understandable when you use this method.
 +///
 +/// # Example
 +///
 +/// ```ignore
 +/// error: usage of mem::forget on Drop type
 +///   --> $DIR/mem_forget.rs:17:5
 +///    |
 +/// 17 |     std::mem::forget(seven);
 +///    |     ^^^^^^^^^^^^^^^^^^^^^^^
 +/// ```
 +pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
 +    cx.struct_span_lint(lint, sp, |diag| {
 +        let mut diag = diag.build(msg);
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +/// Same as `span_lint` but with an extra `help` message.
 +///
 +/// Use this if you want to provide some general help but
 +/// can't provide a specific machine applicable suggestion.
 +///
 +/// The `help` message can be optionally attached to a `Span`.
 +///
 +/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 +///
 +/// # Example
 +///
 +/// ```ignore
 +/// error: constant division of 0.0 with 0.0 will always result in NaN
 +///   --> $DIR/zero_div_zero.rs:6:25
 +///    |
 +/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
 +///    |                         ^^^^^^^^^^^^
 +///    |
 +///    = help: Consider using `f64::NAN` if you would like a constant representing NaN
 +/// ```
 +pub fn span_lint_and_help<'a, T: LintContext>(
 +    cx: &'a T,
 +    lint: &'static Lint,
 +    span: Span,
 +    msg: &str,
 +    help_span: Option<Span>,
 +    help: &str,
 +) {
 +    cx.struct_span_lint(lint, span, |diag| {
 +        let mut diag = diag.build(msg);
 +        if let Some(help_span) = help_span {
 +            diag.span_help(help_span, help);
 +        } else {
 +            diag.help(help);
 +        }
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +/// Like `span_lint` but with a `note` section instead of a `help` message.
 +///
 +/// The `note` message is presented separately from the main lint message
 +/// and is attached to a specific span:
 +///
 +/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 +///
 +/// # Example
 +///
 +/// ```ignore
 +/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
 +///   --> $DIR/drop_forget_ref.rs:10:5
 +///    |
 +/// 10 |     forget(&SomeStruct);
 +///    |     ^^^^^^^^^^^^^^^^^^^
 +///    |
 +///    = note: `-D clippy::forget-ref` implied by `-D warnings`
 +/// note: argument has type &SomeStruct
 +///   --> $DIR/drop_forget_ref.rs:10:12
 +///    |
 +/// 10 |     forget(&SomeStruct);
 +///    |            ^^^^^^^^^^^
 +/// ```
 +pub fn span_lint_and_note<'a, T: LintContext>(
 +    cx: &'a T,
 +    lint: &'static Lint,
++    span: impl Into<MultiSpan>,
 +    msg: &str,
 +    note_span: Option<Span>,
 +    note: &str,
 +) {
 +    cx.struct_span_lint(lint, span, |diag| {
 +        let mut diag = diag.build(msg);
 +        if let Some(note_span) = note_span {
 +            diag.span_note(note_span, note);
 +        } else {
 +            diag.note(note);
 +        }
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
 +///
 +/// If you need to customize your lint output a lot, use this function.
 +/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
 +where
 +    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
 +{
 +    cx.struct_span_lint(lint, sp, |diag| {
 +        let mut diag = diag.build(msg);
 +        f(&mut diag);
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
 +    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
 +        let mut diag = diag.build(msg);
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +pub fn span_lint_hir_and_then(
 +    cx: &LateContext<'_>,
 +    lint: &'static Lint,
 +    hir_id: HirId,
 +    sp: Span,
 +    msg: &str,
 +    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
 +) {
 +    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
 +        let mut diag = diag.build(msg);
 +        f(&mut diag);
 +        docs_link(&mut diag, lint);
 +        diag.emit();
 +    });
 +}
 +
 +/// Add a span lint with a suggestion on how to fix it.
 +///
 +/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
 +/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
 +/// 2)"`.
 +///
 +/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 +///
 +/// # Example
 +///
 +/// ```ignore
 +/// error: This `.fold` can be more succinctly expressed as `.any`
 +/// --> $DIR/methods.rs:390:13
 +///     |
 +/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
 +///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
 +///     |
 +///     = note: `-D fold-any` implied by `-D warnings`
 +/// ```
 +#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
 +pub fn span_lint_and_sugg<'a, T: LintContext>(
 +    cx: &'a T,
 +    lint: &'static Lint,
 +    sp: Span,
 +    msg: &str,
 +    help: &str,
 +    sugg: String,
 +    applicability: Applicability,
 +) {
 +    span_lint_and_then(cx, lint, sp, msg, |diag| {
 +        diag.span_suggestion(sp, help, sugg, applicability);
 +    });
 +}
 +
 +/// Create a suggestion made from several `span → replacement`.
 +///
 +/// Note: in the JSON format (used by `compiletest_rs`), the help message will
 +/// appear once per
 +/// replacement. In human-readable format though, it only appears once before
 +/// the whole suggestion.
 +pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I)
 +where
 +    I: IntoIterator<Item = (Span, String)>,
 +{
 +    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
 +}
 +
 +pub fn multispan_sugg_with_applicability<I>(
 +    diag: &mut DiagnosticBuilder<'_>,
 +    help_msg: &str,
 +    applicability: Applicability,
 +    sugg: I,
 +) where
 +    I: IntoIterator<Item = (Span, String)>,
 +{
 +    diag.multipart_suggestion(help_msg, sugg.into_iter().collect(), applicability);
 +}
index 822863ca3e279d5039077bf78ac9bbbb4038a93c,0000000000000000000000000000000000000000..cccad243e1b5917a1c52b4d34979a9fdc4626345
mode 100644,000000..100644
--- /dev/null
@@@ -1,1072 -1,0 +1,1072 @@@
-             if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id());
 +use crate::consts::{constant_simple, Constant};
 +use crate::utils::{
 +    is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, run_lints, snippet,
 +    span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
 +};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
 +use rustc_ast::visit::FnKind;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::CRATE_HIR_ID;
 +use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 +use rustc_hir::{
 +    BinOpKind, Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Node, Path, StmtKind, Ty, TyKind, UnOp,
 +};
 +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::mir::interpret::ConstValue;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::symbol::{Symbol, SymbolStr};
 +use rustc_typeck::hir_ty_to_ty;
 +
 +use std::borrow::{Borrow, Cow};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for various things we like to keep tidy in clippy.
 +    ///
 +    /// **Why is this bad?** We like to pretend we're an example of tidy code.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:** Wrong ordering of the util::paths constants.
 +    pub CLIPPY_LINTS_INTERNAL,
 +    internal,
 +    "various things that will negatively affect your clippy experience"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Ensures every lint is associated to a `LintPass`.
 +    ///
 +    /// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
 +    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
 +    /// know the name of the lint.
 +    ///
 +    /// **Known problems:** Only checks for lints associated using the
 +    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
 +    ///
 +    /// **Example:**
 +    /// ```rust,ignore
 +    /// declare_lint! { pub LINT_1, ... }
 +    /// declare_lint! { pub LINT_2, ... }
 +    /// declare_lint! { pub FORGOTTEN_LINT, ... }
 +    /// // ...
 +    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
 +    /// // missing FORGOTTEN_LINT
 +    /// ```
 +    pub LINT_WITHOUT_LINT_PASS,
 +    internal,
 +    "declaring a lint without associating it in a LintPass"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
 +    /// variant of the function.
 +    ///
 +    /// **Why is this bad?** The `utils::*` variants also add a link to the Clippy documentation to the
 +    /// warning/error messages.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// cx.span_lint(LINT_NAME, "message");
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::span_lint(cx, LINT_NAME, "message");
 +    /// ```
 +    pub COMPILER_LINT_FUNCTIONS,
 +    internal,
 +    "usage of the lint functions of the compiler instead of the utils::* variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for calls to `cx.outer().expn_data()` and suggests to use
 +    /// the `cx.outer_expn_data()`
 +    ///
 +    /// **Why is this bad?** `cx.outer_expn_data()` is faster and more concise.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer().expn_data()
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// expr.span.ctxt().outer_expn_data()
 +    /// ```
 +    pub OUTER_EXPN_EXPN_DATA,
 +    internal,
 +    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Not an actual lint. This lint is only meant for testing our customized internal compiler
 +    /// error message by calling `panic`.
 +    ///
 +    /// **Why is this bad?** ICE in large quantities can damage your teeth
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// 🍦🍦🍦🍦🍦
 +    /// ```
 +    pub PRODUCE_ICE,
 +    internal,
 +    "this message should not appear anywhere as we ICE before and don't emit the lint"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for cases of an auto-generated lint without an updated description,
 +    /// i.e. `default lint description`.
 +    ///
 +    /// **Why is this bad?** Indicates that the lint is not finished.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
 +    /// ```
 +    pub DEFAULT_LINT,
 +    internal,
 +    "found 'default lint description' in a lint declaration"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Lints `span_lint_and_then` function calls, where the
 +    /// closure argument has only one statement and that statement is a method
 +    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
 +    /// span), `help` or `note`.
 +    ///
 +    /// These usages of `span_lint_and_then` should be replaced with one of the
 +    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
 +    /// `span_lint_and_note`.
 +    ///
 +    /// **Why is this bad?** Using the wrapper `span_lint_and_*` functions, is more
 +    /// convenient, readable and less error prone.
 +    ///
 +    /// **Known problems:** None
 +    ///
 +    /// *Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_suggestion(
 +    ///         expr.span,
 +    ///         help_msg,
 +    ///         sugg.to_string(),
 +    ///         Applicability::MachineApplicable,
 +    ///     );
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_help(expr.span, help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.help(help_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.span_note(expr.span, note_msg);
 +    /// });
 +    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
 +    ///     diag.note(note_msg);
 +    /// });
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     TEST_LINT,
 +    ///     expr.span,
 +    ///     lint_msg,
 +    ///     help_msg,
 +    ///     sugg.to_string(),
 +    ///     Applicability::MachineApplicable,
 +    /// );
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
 +    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
 +    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
 +    /// ```
 +    pub COLLAPSIBLE_SPAN_LINT_CALLS,
 +    internal,
 +    "found collapsible `span_lint_and_then` calls"
 +}
 +
 +declare_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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// Bad:
 +    /// ```rust,ignore
 +    /// utils::match_type(cx, ty, &paths::VEC)
 +    /// ```
 +    ///
 +    /// Good:
 +    /// ```rust,ignore
 +    /// utils::is_type_diagnostic_item(cx, ty, sym::vec_type)
 +    /// ```
 +    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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **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_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
 +
 +impl EarlyLintPass for ClippyLintsInternal {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
 +        if let Some(utils) = krate
 +            .module
 +            .items
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == "utils")
 +        {
 +            if let ItemKind::Mod(ref utils_mod) = utils.kind {
 +                if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name.as_str() == "paths") {
 +                    if let ItemKind::Mod(ref paths_mod) = paths.kind {
 +                        let mut last_name: Option<SymbolStr> = None;
 +                        for item in &*paths_mod.items {
 +                            let name = item.ident.as_str();
 +                            if let Some(ref last_name) = last_name {
 +                                if **last_name > *name {
 +                                    span_lint(
 +                                        cx,
 +                                        CLIPPY_LINTS_INTERNAL,
 +                                        item.span,
 +                                        "this constant should be before the previous constant due to lexical \
 +                                         ordering",
 +                                    );
 +                                }
 +                            }
 +                            last_name = Some(name);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[derive(Clone, Debug, Default)]
 +pub struct LintWithoutLintPass {
 +    declared_lints: FxHashMap<Symbol, Span>,
 +    registered_lints: FxHashSet<Symbol>,
 +}
 +
 +impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if !run_lints(cx, &[DEFAULT_LINT], item.hir_id) {
 +            return;
 +        }
 +
 +        if let hir::ItemKind::Static(ref ty, Mutability::Not, body_id) = item.kind {
 +            if is_lint_ref_type(cx, ty) {
 +                let expr = &cx.tcx.hir().body(body_id).value;
 +                if_chain! {
 +                    if let ExprKind::AddrOf(_, _, ref inner_exp) = expr.kind;
 +                    if let ExprKind::Struct(_, ref fields, _) = inner_exp.kind;
 +                    let field = fields
 +                        .iter()
 +                        .find(|f| f.ident.as_str() == "desc")
 +                        .expect("lints must have a description field");
 +                    if let ExprKind::Lit(Spanned {
 +                        node: LitKind::Str(ref sym, _),
 +                        ..
 +                    }) = field.expr.kind;
 +                    if sym.as_str() == "default lint description";
 +
 +                    then {
 +                        span_lint(
 +                            cx,
 +                            DEFAULT_LINT,
 +                            item.span,
 +                            &format!("the lint `{}` has the default lint description", item.ident.name),
 +                        );
 +                    }
 +                }
 +                self.declared_lints.insert(item.ident.name, item.span);
 +            }
 +        } else if is_expn_of(item.span, "impl_lint_pass").is_some()
 +            || is_expn_of(item.span, "declare_lint_pass").is_some()
 +        {
 +            if let hir::ItemKind::Impl(hir::Impl {
 +                of_trait: None,
 +                items: ref impl_item_refs,
 +                ..
 +            }) = item.kind
 +            {
 +                let mut collector = LintCollector {
 +                    output: &mut self.registered_lints,
 +                    cx,
 +                };
 +                let body_id = cx.tcx.hir().body_owned_by(
 +                    impl_item_refs
 +                        .iter()
 +                        .find(|iiref| iiref.ident.as_str() == "get_lints")
 +                        .expect("LintPass needs to implement get_lints")
 +                        .id
 +                        .hir_id,
 +                );
 +                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
 +            }
 +        }
 +    }
 +
 +    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
 +        if !run_lints(cx, &[LINT_WITHOUT_LINT_PASS], CRATE_HIR_ID) {
 +            return;
 +        }
 +
 +        for (lint_name, &lint_span) in &self.declared_lints {
 +            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
 +            // file points to "<rustc macros>".
 +            // `compiletest-rs` thinks that's an error in a different file and
 +            // just ignores it. This causes the test in compile-fail/lint_pass
 +            // not able to capture the error.
 +            // Therefore, we need to climb the macro expansion tree and find the
 +            // actual span that invoked `declare_tool_lint!`:
 +            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
 +
 +            if !self.registered_lints.contains(lint_name) {
 +                span_lint(
 +                    cx,
 +                    LINT_WITHOUT_LINT_PASS,
 +                    lint_span,
 +                    &format!("the lint `{}` is not added to any `LintPass`", lint_name),
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
 +    if let TyKind::Rptr(
 +        _,
 +        MutTy {
 +            ty: ref inner,
 +            mutbl: Mutability::Not,
 +        },
 +    ) = ty.kind
 +    {
 +        if let TyKind::Path(ref path) = inner.kind {
 +            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
 +                return match_def_path(cx, def_id, &paths::LINT);
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +struct LintCollector<'a, 'tcx> {
 +    output: &'a mut FxHashSet<Symbol>,
 +    cx: &'a LateContext<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
 +        if path.segments.len() == 1 {
 +            self.output.insert(path.segments[0].ident.name);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +}
 +
 +#[derive(Clone, Default)]
 +pub struct CompilerLintFunctions {
 +    map: FxHashMap<&'static str, &'static str>,
 +}
 +
 +impl CompilerLintFunctions {
 +    #[must_use]
 +    pub fn new() -> Self {
 +        let mut map = FxHashMap::default();
 +        map.insert("span_lint", "utils::span_lint");
 +        map.insert("struct_span_lint", "utils::span_lint");
 +        map.insert("lint", "utils::span_lint");
 +        map.insert("span_lint_note", "utils::span_lint_and_note");
 +        map.insert("span_lint_help", "utils::span_lint_and_help");
 +        Self { map }
 +    }
 +}
 +
 +impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if !run_lints(cx, &[COMPILER_LINT_FUNCTIONS], expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
 +            let fn_name = path.ident;
 +            if let Some(sugg) = self.map.get(&*fn_name.as_str());
 +            let ty = cx.typeck_results().expr_ty(&args[0]).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 !run_lints(cx, &[OUTER_EXPN_EXPN_DATA], expr.hir_id) {
 +            return;
 +        }
 +
 +        let (method_names, arg_lists, spans) = method_calls(expr, 2);
 +        let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
 +        let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
 +        if_chain! {
 +            if let ["expn_data", "outer_expn"] = method_names.as_slice();
 +            let args = arg_lists[1];
 +            if args.len() == 1;
 +            let self_arg = &args[0];
 +            let self_ty = 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) {
 +        if is_trigger_fn(fn_kind) {
 +            panic!("Would you like some help with that?");
 +        }
 +    }
 +}
 +
 +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
 +        FnKind::Closure(..) => false,
 +    }
 +}
 +
 +declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
 +        if !run_lints(cx, &[COLLAPSIBLE_SPAN_LINT_CALLS], expr.hir_id) {
 +            return;
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::Call(ref func, ref and_then_args) = expr.kind;
 +            if let ExprKind::Path(ref path) = func.kind;
 +            if match_qpath(path, &["span_lint_and_then"]);
 +            if and_then_args.len() == 5;
 +            if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
 +            let body = cx.tcx.hir().body(*body_id);
 +            if let ExprKind::Block(block, _) = &body.value.kind;
 +            let stmts = &block.stmts;
 +            if stmts.len() == 1 && block.expr.is_none();
 +            if let StmtKind::Semi(only_expr) = &stmts[0].kind;
 +            if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind;
 +            let and_then_snippets = get_and_then_snippets(cx, and_then_args);
 +            let mut sle = SpanlessEq::new(cx).deny_side_effects();
 +            then {
 +                match &*ps.ident.as_str() {
 +                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
 +                    },
 +                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
 +                    },
 +                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
 +                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
 +                    },
 +                    "help" => {
 +                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
 +                    }
 +                    "note" => {
 +                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
 +                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
 +                    }
 +                    _  => (),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct AndThenSnippets<'a> {
 +    cx: Cow<'a, str>,
 +    lint: Cow<'a, str>,
 +    span: Cow<'a, str>,
 +    msg: Cow<'a, str>,
 +}
 +
 +fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
 +    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
 +    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
 +    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
 +    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
 +
 +    AndThenSnippets {
 +        cx: cx_snippet,
 +        lint: lint_snippet,
 +        span: span_snippet,
 +        msg: msg_snippet,
 +    }
 +}
 +
 +struct SpanSuggestionSnippets<'a> {
 +    help: Cow<'a, str>,
 +    sugg: Cow<'a, str>,
 +    applicability: Cow<'a, str>,
 +}
 +
 +fn span_suggestion_snippets<'a, 'hir>(
 +    cx: &LateContext<'_>,
 +    span_call_args: &'hir [Expr<'hir>],
 +) -> SpanSuggestionSnippets<'a> {
 +    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
 +    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
 +    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
 +
 +    SpanSuggestionSnippets {
 +        help: help_snippet,
 +        sugg: sugg_snippet,
 +        applicability: applicability_snippet,
 +    }
 +}
 +
 +fn suggest_suggestion(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
 +) {
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            span_suggestion_snippets.help,
 +            span_suggestion_snippets.sugg,
 +            span_suggestion_snippets.applicability
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_help(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    help: &str,
 +    with_span: bool,
 +) {
 +    let option_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collapsible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_help({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            &option_span,
 +            help
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +fn suggest_note(
 +    cx: &LateContext<'_>,
 +    expr: &Expr<'_>,
 +    and_then_snippets: &AndThenSnippets<'_>,
 +    note: &str,
 +    with_span: bool,
 +) {
 +    let note_span = if with_span {
 +        format!("Some({})", and_then_snippets.span)
 +    } else {
 +        "None".to_string()
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        COLLAPSIBLE_SPAN_LINT_CALLS,
 +        expr.span,
 +        "this call is collspible",
 +        "collapse into",
 +        format!(
 +            "span_lint_and_note({}, {}, {}, {}, {}, {})",
 +            and_then_snippets.cx,
 +            and_then_snippets.lint,
 +            and_then_snippets.span,
 +            and_then_snippets.msg,
 +            note_span,
 +            note
 +        ),
 +        Applicability::MachineApplicable,
 +    );
 +}
 +
 +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 !run_lints(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 let ExprKind::Path(fn_qpath) = &fn_path.kind;
 +            if match_qpath(&fn_qpath, &["utils", "match_type"]);
 +            // Extract the path to the matched type
 +            if let Some(segments) = path_to_matched_type(cx, ty_path);
 +            let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
-     if path_to_res(cx, path).is_some() {
++            if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
 +            // Check if the matched type is a diagnostic item
 +            let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
 +            if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
 +            then {
 +                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 `utils::match_type()` on a type diagnostic item",
 +                    "try",
 +                    format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
 +                    Applicability::MaybeIncorrect,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<SymbolStr>> {
 +    use rustc_hir::ItemKind;
 +
 +    match &expr.kind {
 +        ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
 +        ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
 +            Res::Local(hir_id) => {
 +                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
 +                if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
 +                    if let Some(init) = local.init {
 +                        return path_to_matched_type(cx, init);
 +                    }
 +                }
 +            },
 +            Res::Def(DefKind::Const | DefKind::Static, def_id) => {
 +                if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
 +                    if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
 +                        let body = cx.tcx.hir().body(body_id);
 +                        return path_to_matched_type(cx, &body.value);
 +                    }
 +                }
 +            },
 +            _ => {},
 +        },
 +        ExprKind::Array(exprs) => {
 +            let segments: Vec<SymbolStr> = exprs
 +                .iter()
 +                .filter_map(|expr| {
 +                    if let ExprKind::Lit(lit) = &expr.kind {
 +                        if let LitKind::Str(sym, _) = lit.node {
 +                            return Some(sym.as_str());
 +                        }
 +                    }
 +
 +                    None
 +                })
 +                .collect();
 +
 +            if segments.len() == exprs.len() {
 +                return Some(segments);
 +            }
 +        },
 +        _ => {},
 +    }
 +
 +    None
 +}
 +
 +// This is not a complete resolver for paths. It works on all the paths currently used in the paths
 +// module.  That's all it does and all it needs to do.
 +pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-             if let Some(Res::Def(_, def_id)) = path_to_res(cx, module) {
++    if path_to_res(cx, path) != Res::Err {
 +        return true;
 +    }
 +
 +    // Some implementations can't be found by `path_to_res`, particularly inherent
 +    // implementations of native types. Check lang items.
 +    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
 +    let lang_items = cx.tcx.lang_items();
 +    for lang_item in lang_items.items() {
 +        if let Some(def_id) = lang_item {
 +            let lang_item_path = cx.get_def_path(*def_id);
 +            if path_syms.starts_with(&lang_item_path) {
 +                if let [item] = &path_syms[lang_item_path.len()..] {
 +                    for child in cx.tcx.item_children(*def_id) {
 +                        if child.ident.name == *item {
 +                            return true;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let local_def_id = &cx.tcx.parent_module(item.hir_id);
 +        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
 +        if_chain! {
 +            if mod_name.as_str() == "paths";
 +            if let hir::ItemKind::Const(ty, body_id) = item.kind;
 +            let ty = hir_ty_to_ty(cx.tcx, ty);
 +            if let ty::Array(el_ty, _) = &ty.kind();
 +            if let ty::Ref(_, el_ty, _) = &el_ty.kind();
 +            if el_ty.is_str();
 +            let body = cx.tcx.hir().body(body_id);
 +            let typeck_results = cx.tcx.typeck_body(body_id);
 +            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value);
 +            let path: Vec<&str> = path.iter().map(|x| {
 +                    if let Constant::Str(s) = x {
 +                        s.as_str()
 +                    } else {
 +                        // We checked the type of the constant above
 +                        unreachable!()
 +                    }
 +                }).collect();
 +            if !check_path(cx, &path[..]);
 +            then {
 +                span_lint(cx, CLIPPY_LINTS_INTERNAL, 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<'_>, _: &Crate<'_>) {
 +        if !self.symbol_map.is_empty() {
 +            return;
 +        }
 +
 +        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
++            if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
 +                for item in cx.tcx.item_children(def_id).iter() {
 +                    if_chain! {
 +                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
 +                        let ty = cx.tcx.type_of(item_def_id);
 +                        if match_type(cx, ty, &paths::SYMBOL);
 +                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
 +                        if let Ok(value) = value.to_u32();
 +                        then {
 +                            self.symbol_map.insert(value, item_def_id);
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::Call(func, [arg]) = &expr.kind;
 +            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
 +            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
 +            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
 +            let value = Symbol::intern(&arg).as_u32();
 +            if let Some(&def_id) = self.symbol_map.get(&value);
 +            then {
 +                span_lint_and_sugg(
 +                    cx,
 +                    INTERNING_DEFINED_SYMBOL,
 +                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
 +                    "interning a defined symbol",
 +                    "try",
 +                    cx.tcx.def_path_str(def_id),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +        if let ExprKind::Binary(op, left, right) = expr.kind {
 +            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
 +                let data = [
 +                    (left, self.symbol_str_expr(left, cx)),
 +                    (right, self.symbol_str_expr(right, cx)),
 +                ];
 +                match data {
 +                    // both operands are a symbol string
 +                    [(_, Some(left)), (_, Some(right))] => {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            UNNECESSARY_SYMBOL_STR,
 +                            expr.span,
 +                            "unnecessary `Symbol` to string conversion",
 +                            "try",
 +                            format!(
 +                                "{} {} {}",
 +                                left.as_symbol_snippet(cx),
 +                                op.node.as_str(),
 +                                right.as_symbol_snippet(cx),
 +                            ),
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                    // one of the operands is a symbol string
 +                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
 +                        // creating an owned string for comparison
 +                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
 +                            span_lint_and_sugg(
 +                                cx,
 +                                UNNECESSARY_SYMBOL_STR,
 +                                expr.span,
 +                                "unnecessary string allocation",
 +                                "try",
 +                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
 +                                Applicability::MachineApplicable,
 +                            );
 +                        }
 +                    },
 +                    // nothing found
 +                    [(_, None), (_, None)] => {},
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +impl InterningDefinedSymbol {
 +    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
 +        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
 +        static SYMBOL_STR_PATHS: &[&[&str]] = &[
 +            &paths::SYMBOL_AS_STR,
 +            &paths::SYMBOL_TO_IDENT_STRING,
 +            &paths::TO_STRING_METHOD,
 +        ];
 +        // SymbolStr might be de-referenced: `&*symbol.as_str()`
 +        let call = if_chain! {
 +            if let ExprKind::AddrOf(_, _, e) = expr.kind;
 +            if let ExprKind::Unary(UnOp::UnDeref, 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
 +            },
 +        }
 +    }
 +}
index d0db3a67533bc5ead8907482817ff0b193d95693,0000000000000000000000000000000000000000..ef45f9fdcd5d49a29e1836ad784351c5f88fe48c
mode 100644,000000..100644
--- /dev/null
@@@ -1,1798 -1,0 +1,1801 @@@
- pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
 +#[macro_use]
 +pub mod sym_helper;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
 +pub mod author;
 +pub mod camel_case;
 +pub mod comparisons;
 +pub mod conf;
 +pub mod constants;
 +mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +pub mod inspector;
 +#[cfg(feature = "internal-lints")]
 +pub mod internal_lints;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod qualify_min_const_fn;
 +pub mod sugg;
 +pub mod usage;
 +pub mod visitors;
 +
 +pub use self::attrs::*;
 +pub use self::diagnostics::*;
 +pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::borrow::Cow;
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 +use rustc_hir::Node;
 +use rustc_hir::{
 +    def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind,
 +    MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety,
 +};
 +use rustc_infer::infer::TyCtxtInferExt;
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::exports::Export;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 +use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
 +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::{BytePos, Pos, Span, DUMMY_SP};
 +use rustc_target::abi::Integer;
 +use rustc_trait_selection::traits::query::normalize::AtExt;
 +use smallvec::SmallVec;
 +
 +use crate::consts::{constant, Constant};
 +
 +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_rules! extract_msrv_attr {
 +    (LateContext) => {
 +        extract_msrv_attr!(@LateContext, ());
 +    };
 +    (EarlyContext) => {
 +        extract_msrv_attr!(@EarlyContext);
 +    };
 +    (@$context:ident$(, $call:tt)?) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
 +            use $crate::utils::get_unique_inner_attr;
 +            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
 +                Some(msrv_attr) => {
 +                    if let Some(msrv) = msrv_attr.value_str() {
 +                        self.msrv = $crate::utils::parse_msrv(
 +                            &msrv.to_string(),
 +                            Some(cx.sess$($call)?),
 +                            Some(msrv_attr.span),
 +                        );
 +                    } else {
 +                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
 +                    }
 +                },
 +                _ => (),
 +            }
 +        }
 +    };
 +}
 +
 +/// Returns `true` if the two spans come from differing expansions (i.e., one is
 +/// from a macro and one isn't).
 +#[must_use]
 +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
 +    rhs.ctxt() != lhs.ctxt()
 +}
 +
 +/// Returns `true` if the given `NodeId` is inside a constant context
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// if in_constant(cx, expr.hir_id) {
 +///     // Do something
 +/// }
 +/// ```
 +pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
 +    let parent_id = cx.tcx.hir().get_parent_item(id);
 +    match cx.tcx.hir().get(parent_id) {
 +        Node::Item(&Item {
 +            kind: ItemKind::Const(..) | ItemKind::Static(..),
 +            ..
 +        })
 +        | Node::TraitItem(&TraitItem {
 +            kind: TraitItemKind::Const(..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Const(..),
 +            ..
 +        })
 +        | Node::AnonConst(_) => true,
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(ref sig, ..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(ref sig, _),
 +            ..
 +        }) => sig.header.constness == Constness::Const,
 +        _ => false,
 +    }
 +}
 +
 +/// Returns `true` if this `span` was expanded by any macro.
 +#[must_use]
 +pub fn in_macro(span: Span) -> bool {
 +    if span.from_expansion() {
 +        !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
 +    } else {
 +        false
 +    }
 +}
 +
 +// If the snippet is empty, it's an attribute that was inserted during macro
 +// expansion and we want to ignore those, because they could come from external
 +// sources that the user has no control over.
 +// For some reason these attributes don't have any expansion info on them, so
 +// we have to check it this way until there is a better way.
 +pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
 +    if let Some(snippet) = snippet_opt(cx, span) {
 +        if snippet.is_empty() {
 +            return false;
 +        }
 +    }
 +    true
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// Checks if type is struct, enum or union type with the given def path.
 +///
 +/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a diagnostic item
 +///
 +/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
 +pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type is equal to a lang item
 +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
 +    match ty.kind() {
 +        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
 +    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +    let trt_id = cx.tcx.trait_of_item(def_id);
 +    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 +}
 +
 +/// Checks if an expression references a variable of the given name.
 +pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
 +    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
 +        if let [p] = path.segments {
 +            return p.ident.name == var;
 +        }
 +    }
 +    false
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, ref seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
 +    match *path {
 +        QPath::Resolved(_, ref path) => path.segments.get(0),
 +        QPath::TypeRelative(_, ref seg) => Some(seg),
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +/// Matches a `QPath` against a slice of segment string literals.
 +///
 +/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
 +/// `rustc_hir::QPath`.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_qpath(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 +    match *path {
 +        QPath::Resolved(_, ref path) => match_path(path, segments),
 +        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
 +            TyKind::Path(ref inner_path) => {
 +                if let [prefix @ .., end] = segments {
 +                    if match_qpath(inner_path, prefix) {
 +                        return segment.ident.name.as_str() == *end;
 +                    }
 +                }
 +                false
 +            },
 +            _ => false,
 +        },
 +        QPath::LangItem(..) => false,
 +    }
 +}
 +
 +/// Matches a `Path` against a slice of segment string literals.
 +///
 +/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
 +/// `rustc_hir::Path`.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// if match_path(&trait_ref.path, &paths::HASH) {
 +///     // This is the `std::hash::Hash` trait.
 +/// }
 +///
 +/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
 +///     // This is a `rustc_middle::lint::Lint`.
 +/// }
 +/// ```
 +pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// Matches a `Path` against a slice of segment string literals, e.g.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_path_ast(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// Gets the definition associated to a path.
 +#[allow(clippy::shadow_unrelated)] // false positive #6563
-         _ => return None,
++pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
++    macro_rules! try_res {
++        ($e:expr) => {
++            match $e {
++                Some(e) => e,
++                None => return Res::Err,
++            }
++        };
++    }
 +    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
 +        tcx.item_children(def_id)
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == name)
 +    }
 +
 +    let (krate, first, path) = match *path {
 +        [krate, first, ref path @ ..] => (krate, first, path),
-     let krate = crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)?;
-     let first = item_child_by_name(tcx, krate.as_def_id(), first)?;
++        _ => return Res::Err,
 +    };
 +    let tcx = cx.tcx;
 +    let crates = tcx.crates();
-         })?;
-     Some(last.res)
++    let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
++    let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
 +    let last = path
 +        .iter()
 +        .copied()
 +        // `get_def_path` seems to generate these empty segments for extern blocks.
 +        // We can just ignore them.
 +        .filter(|segment| !segment.is_empty())
 +        // for each segment, find the child item
 +        .try_fold(first, |item, segment| {
 +            let def_id = item.res.def_id();
 +            if let Some(item) = item_child_by_name(tcx, def_id, segment) {
 +                Some(item)
 +            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
 +                // it is not a child item so check inherent impl items
 +                tcx.inherent_impls(def_id)
 +                    .iter()
 +                    .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
 +            } else {
 +                None
 +            }
-     let res = match path_to_res(cx, path) {
-         Some(res) => res,
-         None => return None,
-     };
-     match res {
++        });
++    try_res!(last).res
 +}
 +
 +/// 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> {
-         Res::Err => unreachable!("this trait resolution is impossible: {:?}", &path),
++    match path_to_res(cx, path) {
 +        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
-         ) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(),
 +        _ => None,
 +    }
 +}
 +
 +/// Checks whether a type implements a trait.
 +/// See also `get_trait_def_id`.
 +pub fn implements_trait<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    ty: Ty<'tcx>,
 +    trait_id: DefId,
 +    ty_params: &[GenericArg<'tcx>],
 +) -> bool {
 +    // Do not check on infer_types to avoid panic in evaluate_obligation.
 +    if ty.has_infer_types() {
 +        return false;
 +    }
 +    let ty = cx.tcx.erase_regions(ty);
 +    if ty.has_escaping_bound_vars() {
 +        return false;
 +    }
 +    let ty_params = cx.tcx.mk_substs(ty_params.iter());
 +    cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
 +}
 +
 +/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 +///
 +/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
 +///
 +/// ```rust
 +/// struct Point(isize, isize);
 +///
 +/// impl std::ops::Add for Point {
 +///     type Output = Self;
 +///
 +///     fn add(self, other: Self) -> Self {
 +///         Point(0, 0)
 +///     }
 +/// }
 +/// ```
 +pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != hir::CRATE_HIR_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
 +        if let hir::ItemKind::Impl(impl_) = &item.kind;
 +        then { return impl_.of_trait.as_ref(); }
 +    }
 +    None
 +}
 +
 +/// Checks whether this type implements `Drop`.
 +pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.ty_adt_def() {
 +        Some(def) => def.has_dtor(cx.tcx),
 +        None => false,
 +    }
 +}
 +
 +/// Returns the method names and argument list of nested method call expressions that make up
 +/// `expr`. method/span lists are sorted with the most recent call first.
 +pub fn method_calls<'tcx>(
 +    expr: &'tcx Expr<'tcx>,
 +    max_depth: usize,
 +) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
 +    let mut method_names = Vec::with_capacity(max_depth);
 +    let mut arg_lists = Vec::with_capacity(max_depth);
 +    let mut spans = Vec::with_capacity(max_depth);
 +
 +    let mut current = expr;
 +    for _ in 0..max_depth {
 +        if let ExprKind::MethodCall(path, span, args, _) = &current.kind {
 +            if args.iter().any(|e| e.span.from_expansion()) {
 +                break;
 +            }
 +            method_names.push(path.ident.name);
 +            arg_lists.push(&**args);
 +            spans.push(*span);
 +            current = &args[0];
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    (method_names, arg_lists, spans)
 +}
 +
 +/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 +///
 +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
 +/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 +/// containing the `Expr`s for
 +/// `.bar()` and `.baz()`
 +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
 +    let mut current = expr;
 +    let mut matched = Vec::with_capacity(methods.len());
 +    for method_name in methods.iter().rev() {
 +        // method chains are stored last -> first
 +        if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
 +            if path.ident.name.as_str() == *method_name {
 +                if args.iter().any(|e| e.span.from_expansion()) {
 +                    return None;
 +                }
 +                matched.push(&**args); // build up `matched` backwards
 +                current = &args[0] // go to parent expression
 +            } else {
 +                return None;
 +            }
 +        } else {
 +            return None;
 +        }
 +    }
 +    // Reverse `matched` so that it is in the same order as `methods`.
 +    matched.reverse();
 +    Some(matched)
 +}
 +
 +/// Returns `true` if the provided `def_id` is an entrypoint to a program.
 +pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    cx.tcx
 +        .entry_fn(LOCAL_CRATE)
 +        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
 +}
 +
 +/// Returns `true` if the expression is in the program's `#[panic_handler]`.
 +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    let parent = cx.tcx.hir().get_parent_item(e.hir_id);
 +    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
 +    Some(def_id) == cx.tcx.lang_items().panic_impl()
 +}
 +
 +/// Gets the name of the item the expression is in, if available.
 +pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
 +    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
 +    match cx.tcx.hir().find(parent_id) {
 +        Some(
 +            Node::Item(Item { ident, .. })
 +            | Node::TraitItem(TraitItem { ident, .. })
 +            | Node::ImplItem(ImplItem { ident, .. }),
 +        ) => Some(ident.name),
 +        _ => None,
 +    }
 +}
 +
 +/// Gets the name of a `Pat`, if any.
 +pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
 +    match pat.kind {
 +        PatKind::Binding(.., ref spname, _) => Some(spname.name),
 +        PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
 +        PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
 +        _ => None,
 +    }
 +}
 +
 +struct ContainsName {
 +    name: Symbol,
 +    result: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ContainsName {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_name(&mut self, _: Span, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Checks if an `Expr` contains a certain name.
 +pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
 +    let mut cn = ContainsName { name, result: false };
 +    cn.visit_expr(expr);
 +    cn.result
 +}
 +
 +/// Returns `true` if `expr` contains a return expression
 +pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    struct RetCallFinder {
 +        found: bool,
 +    }
 +
 +    impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
 +        type Map = Map<'tcx>;
 +
 +        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +            if self.found {
 +                return;
 +            }
 +            if let hir::ExprKind::Ret(..) = &expr.kind {
 +                self.found = true;
 +            } else {
 +                hir::intravisit::walk_expr(self, expr);
 +            }
 +        }
 +
 +        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
 +            hir::intravisit::NestedVisitorMap::None
 +        }
 +    }
 +
 +    let mut visitor = RetCallFinder { found: false };
 +    visitor.visit_expr(expr);
 +    visitor.found
 +}
 +
 +struct FindMacroCalls<'a, 'b> {
 +    names: &'a [&'b str],
 +    result: Vec<Span>,
 +}
 +
 +impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
 +            self.result.push(expr.span);
 +        }
 +        // and check sub-expressions
 +        intravisit::walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Finds calls of the specified macros in a function body.
 +pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
 +    let mut fmc = FindMacroCalls {
 +        names,
 +        result: Vec::new(),
 +    };
 +    fmc.visit_expr(&body.value);
 +    fmc.result
 +}
 +
 +/// Converts a span to a code snippet if available, otherwise use default.
 +///
 +/// This is useful if you want to provide suggestions for your lint or more generally, if you want
 +/// to convert a given `Span` to a `str`.
 +///
 +/// # Example
 +/// ```rust,ignore
 +/// snippet(cx, expr.span, "..")
 +/// ```
 +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
 +    snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
 +}
 +
 +/// Same as `snippet`, but it adapts the applicability level by following rules:
 +///
 +/// - Applicability level `Unspecified` will never be changed.
 +/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 +/// - If the default value is used and the applicability level is `MachineApplicable`, change it to
 +/// `HasPlaceholders`
 +pub fn snippet_with_applicability<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    applicability: &mut Applicability,
 +) -> Cow<'a, str> {
 +    if *applicability != Applicability::Unspecified && span.from_expansion() {
 +        *applicability = Applicability::MaybeIncorrect;
 +    }
 +    snippet_opt(cx, span).map_or_else(
 +        || {
 +            if *applicability == Applicability::MachineApplicable {
 +                *applicability = Applicability::HasPlaceholders;
 +            }
 +            Cow::Borrowed(default)
 +        },
 +        From::from,
 +    )
 +}
 +
 +/// Same as `snippet`, but should only be used when it's clear that the input span is
 +/// not a macro argument.
 +pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
 +    snippet(cx, span.source_callsite(), default)
 +}
 +
 +/// Converts a span to a code snippet. Returns `None` if not available.
 +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 +    cx.sess().source_map().span_to_snippet(span).ok()
 +}
 +
 +/// Converts a span (from a block) to a code snippet if available, otherwise use default.
 +///
 +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like
 +/// things which need to be printed as such.
 +///
 +/// The `indent_relative_to` arg can be used, to provide a span, where the indentation of the
 +/// resulting snippet of the given span.
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// snippet_block(cx, block.span, "..", None)
 +/// // where, `block` is the block of the if expr
 +///     if x {
 +///         y;
 +///     }
 +/// // will return the snippet
 +/// {
 +///     y;
 +/// }
 +/// ```
 +///
 +/// ```rust,ignore
 +/// snippet_block(cx, block.span, "..", Some(if_expr.span))
 +/// // where, `block` is the block of the if expr
 +///     if x {
 +///         y;
 +///     }
 +/// // will return the snippet
 +/// {
 +///         y;
 +///     } // aligned with `if`
 +/// ```
 +/// Note that the first line of the snippet always has 0 indentation.
 +pub fn snippet_block<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +) -> Cow<'a, str> {
 +    let snip = snippet(cx, span, default);
 +    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
 +    reindent_multiline(snip, true, indent)
 +}
 +
 +/// Same as `snippet_block`, but adapts the applicability level by the rules of
 +/// `snippet_with_applicability`.
 +pub fn snippet_block_with_applicability<'a, T: LintContext>(
 +    cx: &T,
 +    span: Span,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +    applicability: &mut Applicability,
 +) -> Cow<'a, str> {
 +    let snip = snippet_with_applicability(cx, span, default, applicability);
 +    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
 +    reindent_multiline(snip, true, indent)
 +}
 +
 +/// Returns a new Span that extends the original Span to the first non-whitespace char of the first
 +/// line.
 +///
 +/// ```rust,ignore
 +///     let x = ();
 +/// //          ^^
 +/// // will be converted to
 +///     let x = ();
 +/// //  ^^^^^^^^^^
 +/// ```
 +pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 +}
 +
 +fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
 +    let line_span = line_span(cx, span);
 +    snippet_opt(cx, line_span).and_then(|snip| {
 +        snip.find(|c: char| !c.is_whitespace())
 +            .map(|pos| line_span.lo() + BytePos::from_usize(pos))
 +    })
 +}
 +
 +/// Returns the indentation of the line of a span
 +///
 +/// ```rust,ignore
 +/// let x = ();
 +/// //      ^^ -- will return 0
 +///     let x = ();
 +/// //          ^^ -- will return 4
 +/// ```
 +pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
 +    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 +}
 +
 +/// Returns the positon just before rarrow
 +///
 +/// ```rust,ignore
 +/// fn into(self) -> () {}
 +///              ^
 +/// // in case of unformatted code
 +/// fn into2(self)-> () {}
 +///               ^
 +/// fn into3(self)   -> () {}
 +///               ^
 +/// ```
 +pub fn position_before_rarrow(s: &str) -> Option<usize> {
 +    s.rfind("->").map(|rpos| {
 +        let mut rpos = rpos;
 +        let chars: Vec<char> = s.chars().collect();
 +        while rpos > 1 {
 +            if let Some(c) = chars.get(rpos - 1) {
 +                if c.is_whitespace() {
 +                    rpos -= 1;
 +                    continue;
 +                }
 +            }
 +            break;
 +        }
 +        rpos
 +    })
 +}
 +
 +/// Extends the span to the beginning of the spans line, incl. whitespaces.
 +///
 +/// ```rust,ignore
 +///        let x = ();
 +/// //             ^^
 +/// // will be converted to
 +///        let x = ();
 +/// // ^^^^^^^^^^^^^^
 +/// ```
 +fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    let span = original_sp(span, DUMMY_SP);
 +    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
 +    let line_no = source_map_and_line.line;
 +    let line_start = source_map_and_line.sf.lines[line_no];
 +    Span::new(line_start, span.hi(), span.ctxt())
 +}
 +
 +/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 +/// Also takes an `Option<String>` which can be put inside the braces.
 +pub fn expr_block<'a, T: LintContext>(
 +    cx: &T,
 +    expr: &Expr<'_>,
 +    option: Option<String>,
 +    default: &'a str,
 +    indent_relative_to: Option<Span>,
 +) -> Cow<'a, str> {
 +    let code = snippet_block(cx, expr.span, default, indent_relative_to);
 +    let string = option.unwrap_or_default();
 +    if expr.span.from_expansion() {
 +        Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
 +    } else if let ExprKind::Block(_, _) = expr.kind {
 +        Cow::Owned(format!("{}{}", code, string))
 +    } else if string.is_empty() {
 +        Cow::Owned(format!("{{ {} }}", code))
 +    } else {
 +        Cow::Owned(format!("{{\n{};\n{}\n}}", code, string))
 +    }
 +}
 +
 +/// Reindent a multiline string with possibility of ignoring the first line.
 +#[allow(clippy::needless_pass_by_value)]
 +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
 +    let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' ');
 +    let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t');
 +    reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into()
 +}
 +
 +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String {
 +    let x = s
 +        .lines()
 +        .skip(ignore_first as usize)
 +        .filter_map(|l| {
 +            if l.is_empty() {
 +                None
 +            } else {
 +                // ignore empty lines
 +                Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0)
 +            }
 +        })
 +        .min()
 +        .unwrap_or(0);
 +    let indent = indent.unwrap_or(0);
 +    s.lines()
 +        .enumerate()
 +        .map(|(i, l)| {
 +            if (ignore_first && i == 0) || l.is_empty() {
 +                l.to_owned()
 +            } else if x > indent {
 +                l.split_at(x - indent).1.to_owned()
 +            } else {
 +                " ".repeat(indent - x) + l
 +            }
 +        })
 +        .collect::<Vec<String>>()
 +        .join("\n")
 +}
 +
 +/// 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>> {
 +    let map = &cx.tcx.hir();
 +    let hir_id = e.hir_id;
 +    let parent_id = map.get_parent_node(hir_id);
 +    if hir_id == parent_id {
 +        return None;
 +    }
 +    map.find(parent_id).and_then(|node| {
 +        if let Node::Expr(parent) = node {
 +            Some(parent)
 +        } else {
 +            None
 +        }
 +    })
 +}
 +
 +pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
 +    let map = &cx.tcx.hir();
 +    let enclosing_node = map
 +        .get_enclosing_scope(hir_id)
 +        .and_then(|enclosing_id| map.find(enclosing_id));
 +    enclosing_node.and_then(|node| match node {
 +        Node::Block(block) => Some(block),
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(_, _, eid),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(_, eid),
 +            ..
 +        }) => match cx.tcx.hir().body(eid).value.kind {
 +            ExprKind::Block(ref block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Returns the base type for HIR references and pointers.
 +pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 +    match ty.kind {
 +        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
 +        _ => ty,
 +    }
 +}
 +
 +/// Returns the base type for references and raw pointers, and count reference
 +/// depth.
 +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
 +        match ty.kind() {
 +            ty::Ref(_, ty, _) => inner(ty, depth + 1),
 +            _ => (ty, depth),
 +        }
 +    }
 +    inner(ty, 0)
 +}
 +
 +/// Checks whether the given expression is a constant integer of the given value.
 +/// unlike `is_integer_literal`, this version does const folding
 +pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
 +    if is_integer_literal(e, value) {
 +        return true;
 +    }
 +    let map = cx.tcx.hir();
 +    let parent_item = map.get_parent_item(e.hir_id);
 +    if let Some((Constant::Int(v), _)) = map
 +        .maybe_body_owned_by(parent_item)
 +        .and_then(|body_id| constant(cx, cx.tcx.typeck_body(body_id), e))
 +    {
 +        value == v
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Checks whether the given expression is a constant literal of the given value.
 +pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 +    // FIXME: use constant folding
 +    if let ExprKind::Lit(ref spanned) = expr.kind {
 +        if let LitKind::Int(v, _) = spanned.node {
 +            return v == value;
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if the given `Expr` has been coerced before.
 +///
 +/// Examples of coercions can be found in the Nomicon at
 +/// <https://doc.rust-lang.org/nomicon/coercions.html>.
 +///
 +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
 +/// information on adjustments and coercions.
 +pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    cx.typeck_results().adjustments().get(e.hir_id).is_some()
 +}
 +
 +/// Returns the pre-expansion span if is this comes from an expansion of the
 +/// macro `name`.
 +/// See also `is_direct_expn_of`.
 +#[must_use]
 +pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 +    loop {
 +        if span.from_expansion() {
 +            let data = span.ctxt().outer_expn_data();
 +            let new_span = data.call_site;
 +
 +            if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +                if mac_name.as_str() == name {
 +                    return Some(new_span);
 +                }
 +            }
 +
 +            span = new_span;
 +        } else {
 +            return None;
 +        }
 +    }
 +}
 +
 +/// Returns the pre-expansion span if the span directly comes from an expansion
 +/// of the macro `name`.
 +/// The difference with `is_expn_of` is that in
 +/// ```rust,ignore
 +/// foo!(bar!(42));
 +/// ```
 +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 +/// `bar!` by
 +/// `is_direct_expn_of`.
 +#[must_use]
 +pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 +    if span.from_expansion() {
 +        let data = span.ctxt().outer_expn_data();
 +        let new_span = data.call_site;
 +
 +        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +            if mac_name.as_str() == name {
 +                return Some(new_span);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Convenience function to get the return type of a function.
 +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
 +    cx.tcx.erase_late_bound_regions(ret_ty)
 +}
 +
 +/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
 +pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool {
 +    ty.walk().any(|inner| match inner.unpack() {
 +        GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty),
 +        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
 +    })
 +}
 +
 +/// Returns `true` if the given type is an `unsafe` function.
 +pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
 +        _ => false,
 +    }
 +}
 +
 +pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
 +}
 +
 +/// Checks if an expression is constructing a tuple-like enum variant or struct
 +pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(ref fun, _) = expr.kind {
 +        if let ExprKind::Path(ref qp) = fun.kind {
 +            let res = cx.qpath_res(qp, fun.hir_id);
 +            return match res {
 +                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
 +                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
 +                _ => false,
 +            };
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if a pattern is refutable.
 +// TODO: should be implemented using rustc/mir_build/thir machinery
 +pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 +    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
 +        matches!(
 +            cx.qpath_res(qpath, id),
 +            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
 +        )
 +    }
 +
 +    fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut i: I) -> bool {
 +        i.any(|pat| is_refutable(cx, pat))
 +    }
 +
 +    match pat.kind {
 +        PatKind::Wild => false,
 +        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
 +        PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
 +        PatKind::Lit(..) | PatKind::Range(..) => true,
 +        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
 +        PatKind::Or(ref pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats.iter().map(|pat| &**pat))
 +        },
 +        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
 +        PatKind::Struct(ref qpath, ref fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, ref pats, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
 +        },
 +        PatKind::Slice(ref head, ref middle, ref tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind() {
 +                ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(sym::automatically_derived))
 +}
 +
 +/// Remove blocks around an expression.
 +///
 +/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 +/// themselves.
 +pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 +    while let ExprKind::Block(ref block, ..) = expr.kind {
 +        match (block.stmts.is_empty(), block.expr.as_ref()) {
 +            (true, Some(e)) => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +pub fn is_self(slf: &Param<'_>) -> bool {
 +    if let PatKind::Binding(.., name, _) = slf.pat.kind {
 +        name.name == kw::SelfLower
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
 +    if_chain! {
 +        if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
 +        if let Res::SelfTy(..) = path.res;
 +        then {
 +            return true
 +        }
 +    }
 +    false
 +}
 +
 +pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
 +    (0..decl.inputs.len()).map(move |i| &body.params[i])
 +}
 +
 +/// Checks if a given expression is a match expression expanded from the `?`
 +/// operator or the `try` macro.
 +pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
 +            if match_qpath(path, &paths::RESULT_OK[1..]);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.kind;
 +            if let Res::Local(lid) = path.res;
 +            if lid == hir_id;
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            match_qpath(path, &paths::RESULT_ERR[1..])
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
 +        if let MatchSource::TryDesugar = *source {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(&arms[0]) && is_err(&arms[1])) ||
 +                (is_ok(&arms[1]) && is_err(&arms[0]));
 +            then {
 +                return Some(expr);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Returns `true` if the lint is allowed in the current context
 +///
 +/// Useful for skipping long running code when it's unnecessary
 +pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn get_arg_name(pat: &Pat<'_>) -> Option<Symbol> {
 +    match pat.kind {
 +        PatKind::Binding(.., ident, None) => Some(ident.name),
 +        PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
 +        _ => None,
 +    }
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: 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: 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: 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: ty::UintTy) -> u128 {
 +    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +/// Removes block comments from the given `Vec` of lines.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// without_block_comments(vec!["/*", "foo", "*/"]);
 +/// // => vec![]
 +///
 +/// without_block_comments(vec!["bar", "/*", "foo", "*/"]);
 +/// // => vec!["bar"]
 +/// ```
 +pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
 +    let mut without = vec![];
 +
 +    let mut nest_level = 0;
 +
 +    for line in lines {
 +        if line.contains("/*") {
 +            nest_level += 1;
 +            continue;
 +        } else if line.contains("*/") {
 +            nest_level -= 1;
 +            continue;
 +        }
 +
 +        if nest_level == 0 {
 +            without.push(line);
 +        }
 +    }
 +
 +    without
 +}
 +
 +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
 +    let map = &tcx.hir();
 +    let mut prev_enclosing_node = None;
 +    let mut enclosing_node = node;
 +    while Some(enclosing_node) != prev_enclosing_node {
 +        if is_automatically_derived(map.attrs(enclosing_node)) {
 +            return true;
 +        }
 +        prev_enclosing_node = Some(enclosing_node);
 +        enclosing_node = map.get_parent_item(enclosing_node);
 +    }
 +    false
 +}
 +
 +/// Returns true if ty has `iter` or `iter_mut` methods
 +pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<&'static str> {
 +    // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
 +    // exists and has the desired signature. Unfortunately FnCtxt is not exported
 +    // so we can't use its `lookup_method` method.
 +    let into_iter_collections: [&[&str]; 13] = [
 +        &paths::VEC,
 +        &paths::OPTION,
 +        &paths::RESULT,
 +        &paths::BTREESET,
 +        &paths::BTREEMAP,
 +        &paths::VEC_DEQUE,
 +        &paths::LINKED_LIST,
 +        &paths::BINARY_HEAP,
 +        &paths::HASHSET,
 +        &paths::HASHMAP,
 +        &paths::PATH_BUF,
 +        &paths::PATH,
 +        &paths::RECEIVER,
 +    ];
 +
 +    let ty_to_check = match probably_ref_ty.kind() {
 +        ty::Ref(_, ty_to_check, _) => ty_to_check,
 +        _ => probably_ref_ty,
 +    };
 +
 +    let def_id = match ty_to_check.kind() {
 +        ty::Array(..) => return Some("array"),
 +        ty::Slice(..) => return Some("slice"),
 +        ty::Adt(adt, _) => adt.did,
 +        _ => return None,
 +    };
 +
 +    for path in &into_iter_collections {
 +        if match_def_path(cx, def_id, path) {
 +            return Some(*path.last().unwrap());
 +        }
 +    }
 +    None
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, 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(ref fun, ref args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        if match_def_path(cx, fun_def_id, path);
 +        then {
 +            return Some(&args)
 +        }
 +    };
 +    None
 +}
 +
 +/// Checks if `Ty` is normalizable. This function is useful
 +/// to avoid crashes on `layout_of`.
 +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
 +    cx.tcx.infer_ctxt().enter(|infcx| {
 +        let cause = rustc_middle::traits::ObligationCause::dummy();
 +        infcx.at(&cause, param_env).normalize(ty).is_ok()
 +    })
 +}
 +
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
 +    // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path`
 +    // accepts only that. We should probably move to Symbols in Clippy as well.
 +    let syms = syms.iter().map(|p| Symbol::intern(p)).collect::<Vec<Symbol>>();
 +    cx.match_def_path(did, &syms)
 +}
 +
 +pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx [Expr<'tcx>]> {
 +    match_function_call(cx, expr, &paths::BEGIN_PANIC)
 +        .or_else(|| match_function_call(cx, expr, &paths::BEGIN_PANIC_FMT))
 +        .or_else(|| match_function_call(cx, expr, &paths::PANIC_ANY))
 +        .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC))
 +        .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_FMT))
 +        .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_STR))
 +}
 +
 +pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
 +    match_def_path(cx, did, &paths::BEGIN_PANIC)
 +        || match_def_path(cx, did, &paths::BEGIN_PANIC_FMT)
 +        || match_def_path(cx, did, &paths::PANIC_ANY)
 +        || match_def_path(cx, did, &paths::PANICKING_PANIC)
 +        || match_def_path(cx, did, &paths::PANICKING_PANIC_FMT)
 +        || match_def_path(cx, did, &paths::PANICKING_PANIC_STR)
 +}
 +
 +/// Returns the list of condition expressions and the list of blocks in a
 +/// sequence of `if/else`.
 +/// E.g., this returns `([a, b], [c, d, e])` for the expression
 +/// `if a { c } else if b { d } else { e }`.
 +pub fn if_sequence<'tcx>(
 +    mut expr: &'tcx Expr<'tcx>,
 +) -> (SmallVec<[&'tcx Expr<'tcx>; 1]>, SmallVec<[&'tcx Block<'tcx>; 1]>) {
 +    let mut conds = SmallVec::new();
 +    let mut blocks: SmallVec<[&Block<'_>; 1]> = SmallVec::new();
 +
 +    while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
 +        conds.push(&**cond);
 +        if let ExprKind::Block(ref block, _) = then_expr.kind {
 +            blocks.push(block);
 +        } else {
 +            panic!("ExprKind::If node is not an ExprKind::Block");
 +        }
 +
 +        if let Some(ref else_expr) = *else_expr {
 +            expr = else_expr;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    // final `else {..}`
 +    if !blocks.is_empty() {
 +        if let ExprKind::Block(ref block, _) = expr.kind {
 +            blocks.push(&**block);
 +        }
 +    }
 +
 +    (conds, blocks)
 +}
 +
 +pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
 +    let map = cx.tcx.hir();
 +    let parent_id = map.get_parent_node(expr.hir_id);
 +    let parent_node = map.get(parent_id);
 +    matches!(
 +        parent_node,
 +        Node::Expr(Expr {
 +            kind: ExprKind::If(_, _, _),
 +            ..
 +        })
 +    )
 +}
 +
 +// Finds the attribute with the given name, if any
 +pub fn attr_by_name<'a>(attrs: &'a [Attribute], name: &'_ str) -> Option<&'a Attribute> {
 +    attrs
 +        .iter()
 +        .find(|attr| attr.ident().map_or(false, |ident| ident.as_str() == name))
 +}
 +
 +// Finds the `#[must_use]` attribute, if any
 +pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 +    attr_by_name(attrs, "must_use")
 +}
 +
 +// Returns whether the type has #[must_use] attribute
 +pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +    match ty.kind() {
 +        ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
 +        ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
 +        ty::Slice(ref ty)
 +        | ty::Array(ref ty, _)
 +        | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
 +        | ty::Ref(_, ref ty, _) => {
 +            // for the Array case we don't need to care for the len == 0 case
 +            // because we don't want to lint functions returning empty arrays
 +            is_must_use_ty(cx, *ty)
 +        },
 +        ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
 +        ty::Opaque(ref def_id, _) => {
 +            for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
 +                if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
 +                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        ty::Dynamic(binder, _) => {
 +            for predicate in binder.iter() {
 +                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
 +                    if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
 +                        return true;
 +                    }
 +                }
 +            }
 +            false
 +        },
 +        _ => false,
 +    }
 +}
 +
 +// check if expr is calling method or function with #[must_use] attribute
 +pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let did = match expr.kind {
 +        ExprKind::Call(ref path, _) => if_chain! {
 +            if let ExprKind::Path(ref qpath) = path.kind;
 +            if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
 +            then {
 +                Some(did)
 +            } else {
 +                None
 +            }
 +        },
 +        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        _ => None,
 +    };
 +
 +    did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
 +}
 +
 +pub fn is_no_std_crate(krate: &Crate<'_>) -> bool {
 +    krate.item.attrs.iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr.path == sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
 +/// ```rust,ignore
 +/// impl Trait for S {
 +///     fn f() {}
 +/// }
 +/// ```
 +pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
 +        matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates =
 +        cx.tcx
 +            .predicates_of(did)
 +            .predicates
 +            .iter()
 +            .filter_map(|(p, _)| if p.is_global() { 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,
 +    }
 +}
 +
 +pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool {
 +    lints.iter().any(|lint| {
 +        matches!(
 +            cx.tcx.lint_level_at_node(lint, id),
 +            (Level::Forbid | Level::Deny | Level::Warn, _)
 +        )
 +    })
 +}
 +
 +/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point
 +/// number type, a str, or an array, slice, or tuple of those types).
 +pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
 +    match ty.kind() {
 +        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
 +        ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
 +        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
 +        ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
 +        _ => false,
 +    }
 +}
 +
 +/// Returns Option<String> where String is a textual representation of the type encapsulated in the
 +/// slice iff the given expression is a slice of primitives (as defined in the
 +/// `is_recursively_primitive_type` function) and None otherwise.
 +pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
 +    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
 +    let expr_kind = expr_type.kind();
 +    let is_primitive = match expr_kind {
 +        ty::Slice(element_type) => is_recursively_primitive_type(element_type),
 +        ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &ty::Slice(_)) => {
 +            if let 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() {
 +            ty::Slice(..) => return Some("slice".into()),
 +            ty::Array(..) => return Some("array".into()),
 +            ty::Tuple(..) => return Some("tuple".into()),
 +            _ => {
 +                // is_recursively_primitive_type() should have taken care
 +                // of the rest and we can rely on the type that is found
 +                let refs_peeled = expr_type.peel_refs();
 +                return Some(refs_peeled.walk().last().unwrap().to_string());
 +            },
 +        }
 +    }
 +    None
 +}
 +
 +/// 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,
 +{
 +    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
 +        return vec![(&exprs[0], &exprs[1])];
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: FxHashMap<_, Vec<&_>> =
 +        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 +
 +    for expr in exprs {
 +        match map.entry(hash(expr)) {
 +            Entry::Occupied(mut o) => {
 +                for o in o.get() {
 +                    if eq(o, expr) {
 +                        match_expr_list.push((o, expr));
 +                    }
 +                }
 +                o.get_mut().push(expr);
 +            },
 +            Entry::Vacant(v) => {
 +                v.insert(vec![expr]);
 +            },
 +        }
 +    }
 +
 +    match_expr_list
 +}
 +
 +/// Peels off all references on the pattern. Returns the underlying pattern and the number of
 +/// references removed.
 +pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
 +        if let PatKind::Ref(pat, _) = pat.kind {
 +            peel(pat, count + 1)
 +        } else {
 +            (pat, count)
 +        }
 +    }
 +    peel(pat, 0)
 +}
 +
 +/// Peels off up to the given number of references on the expression. Returns the underlying
 +/// expression and the number of references removed.
 +pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
 +    fn f(expr: &'a Expr<'a>, count: usize, target: usize) -> (&'a Expr<'a>, usize) {
 +        match expr.kind {
 +            ExprKind::AddrOf(_, _, expr) if count != target => f(expr, count + 1, target),
 +            _ => (expr, count),
 +        }
 +    }
 +    f(expr, 0, count)
 +}
 +
 +/// Peels off all references on the type. Returns the underlying type and the number of references
 +/// removed.
 +pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
 +    fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
 +        if let ty::Ref(_, ty, _) = ty.kind() {
 +            peel(ty, count + 1)
 +        } else {
 +            (ty, count)
 +        }
 +    }
 +    peel(ty, 0)
 +}
 +
 +#[macro_export]
 +macro_rules! unwrap_cargo_metadata {
 +    ($cx: ident, $lint: ident, $deps: expr) => {{
 +        let mut command = cargo_metadata::MetadataCommand::new();
 +        if !$deps {
 +            command.no_deps();
 +        }
 +
 +        match command.exec() {
 +            Ok(metadata) => metadata,
 +            Err(err) => {
 +                span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
 +                return;
 +            },
 +        }
 +    }};
 +}
 +
 +pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if_chain! {
 +        if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
 +        if let Res::Def(_, def_id) = path.res;
 +        then {
 +            cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::{reindent_multiline, without_block_comments};
 +
 +    #[test]
 +    fn test_reindent_multiline_single_line() {
 +        assert_eq!("", reindent_multiline("".into(), false, None));
 +        assert_eq!("...", reindent_multiline("...".into(), false, None));
 +        assert_eq!("...", reindent_multiline("    ...".into(), false, None));
 +        assert_eq!("...", reindent_multiline("\t...".into(), false, None));
 +        assert_eq!("...", reindent_multiline("\t\t...".into(), false, None));
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn test_reindent_multiline_block() {
 +        assert_eq!("\
 +    if x {
 +        y
 +    } else {
 +        z
 +    }", reindent_multiline("    if x {
 +            y
 +        } else {
 +            z
 +        }".into(), false, None));
 +        assert_eq!("\
 +    if x {
 +    \ty
 +    } else {
 +    \tz
 +    }", reindent_multiline("    if x {
 +        \ty
 +        } else {
 +        \tz
 +        }".into(), false, None));
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn test_reindent_multiline_empty_line() {
 +        assert_eq!("\
 +    if x {
 +        y
 +
 +    } else {
 +        z
 +    }", reindent_multiline("    if x {
 +            y
 +
 +        } else {
 +            z
 +        }".into(), false, None));
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn test_reindent_multiline_lines_deeper() {
 +        assert_eq!("\
 +        if x {
 +            y
 +        } else {
 +            z
 +        }", reindent_multiline("\
 +    if x {
 +        y
 +    } else {
 +        z
 +    }".into(), true, Some(8)));
 +    }
 +
 +    #[test]
 +    fn test_without_block_comments_lines_without_block_comments() {
 +        let result = without_block_comments(vec!["/*", "", "*/"]);
 +        println!("result: {:?}", result);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
 +        assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
 +
 +        let result = without_block_comments(vec!["/* rust", "", "*/"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* one-line comment */"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
 +        assert!(result.is_empty());
 +
 +        let result = without_block_comments(vec!["foo", "bar", "baz"]);
 +        assert_eq!(result, vec!["foo", "bar", "baz"]);
 +    }
 +}
index b9e97077c540f46cfeb3c9a3f33e49864dcbb210,0000000000000000000000000000000000000000..978a232bcfb3a132a37ef2d6d09f6b5ede42c02a
mode 100644,000000..100644
--- /dev/null
@@@ -1,575 -1,0 +1,579 @@@
-         if let ItemKind::Impl(box ImplKind { of_trait: Some(trait_ref), .. }) = &item.kind {
 +use std::borrow::Cow;
 +use std::ops::Range;
 +
 +use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{
 +    Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle,
 +};
 +use rustc_ast::token;
 +use rustc_ast::tokenstream::TokenStream;
 +use rustc_errors::Applicability;
 +use rustc_lexer::unescape::{self, EscapeError};
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_parse::parser;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::symbol::kw;
 +use rustc_span::{sym, BytePos, Span};
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `println!("")` to
 +    /// print a newline.
 +    ///
 +    /// **Why is this bad?** You should use `println!()`, which is simpler.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// // Bad
 +    /// println!("");
 +    ///
 +    /// // Good
 +    /// println!();
 +    /// ```
 +    pub PRINTLN_EMPTY_STRING,
 +    style,
 +    "using `println!(\"\")` with an empty string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `print!()` with a format
 +    /// string that ends in a newline.
 +    ///
 +    /// **Why is this bad?** You should use `println!()` instead, which appends the
 +    /// newline.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let name = "World";
 +    /// print!("Hello {}!\n", name);
 +    /// ```
 +    /// use println!() instead
 +    /// ```rust
 +    /// # let name = "World";
 +    /// println!("Hello {}!", name);
 +    /// ```
 +    pub PRINT_WITH_NEWLINE,
 +    style,
 +    "using `print!()` with a format string that ends in a single newline"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for printing on *stdout*. The purpose of this lint
 +    /// is to catch debugging remnants.
 +    ///
 +    /// **Why is this bad?** People often print on *stdout* while debugging an
 +    /// application and might forget to remove those prints afterward.
 +    ///
 +    /// **Known problems:** Only catches `print!` and `println!` calls.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// println!("Hello world!");
 +    /// ```
 +    pub PRINT_STDOUT,
 +    restriction,
 +    "printing on stdout"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for printing on *stderr*. The purpose of this lint
 +    /// is to catch debugging remnants.
 +    ///
 +    /// **Why is this bad?** People often print on *stderr* while debugging an
 +    /// application and might forget to remove those prints afterward.
 +    ///
 +    /// **Known problems:** Only catches `eprint!` and `eprintln!` calls.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// eprintln!("Hello world!");
 +    /// ```
 +    pub PRINT_STDERR,
 +    restriction,
 +    "printing on stderr"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for use of `Debug` formatting. The purpose of this
 +    /// lint is to catch debugging remnants.
 +    ///
 +    /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
 +    /// debugging Rust code. It should not be used in user-facing output.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # let foo = "bar";
 +    /// println!("{:?}", foo);
 +    /// ```
 +    pub USE_DEBUG,
 +    restriction,
 +    "use of `Debug`-based formatting"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
 +    ///
 +    /// **Why is this bad?** Using literals as `println!` args is inefficient
 +    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
 +    /// (i.e., just put the literal in the format string)
 +    ///
 +    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
 +    /// -- e.g., `println!("{}", env!("FOO"))`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// println!("{}", "foo");
 +    /// ```
 +    /// use the literal without formatting:
 +    /// ```rust
 +    /// println!("foo");
 +    /// ```
 +    pub PRINT_LITERAL,
 +    style,
 +    "printing a literal with a format string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `writeln!(buf, "")` to
 +    /// print a newline.
 +    ///
 +    /// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    ///
 +    /// // Bad
 +    /// writeln!(buf, "");
 +    ///
 +    /// // Good
 +    /// writeln!(buf);
 +    /// ```
 +    pub WRITELN_EMPTY_STRING,
 +    style,
 +    "using `writeln!(buf, \"\")` with an empty string"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns when you use `write!()` with a format
 +    /// string that
 +    /// ends in a newline.
 +    ///
 +    /// **Why is this bad?** You should use `writeln!()` instead, which appends the
 +    /// newline.
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    /// # let name = "World";
 +    ///
 +    /// // Bad
 +    /// write!(buf, "Hello {}!\n", name);
 +    ///
 +    /// // Good
 +    /// writeln!(buf, "Hello {}!", name);
 +    /// ```
 +    pub WRITE_WITH_NEWLINE,
 +    style,
 +    "using `write!()` with a format string that ends in a single newline"
 +}
 +
 +declare_clippy_lint! {
 +    /// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
 +    ///
 +    /// **Why is this bad?** Using literals as `writeln!` args is inefficient
 +    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
 +    /// (i.e., just put the literal in the format string)
 +    ///
 +    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
 +    /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
 +    ///
 +    /// **Example:**
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    ///
 +    /// // Bad
 +    /// writeln!(buf, "{}", "foo");
 +    ///
 +    /// // Good
 +    /// writeln!(buf, "foo");
 +    /// ```
 +    pub WRITE_LITERAL,
 +    style,
 +    "writing a literal with a format string"
 +}
 +
 +#[derive(Default)]
 +pub struct Write {
 +    in_debug_impl: bool,
 +}
 +
 +impl_lint_pass!(Write => [
 +    PRINT_WITH_NEWLINE,
 +    PRINTLN_EMPTY_STRING,
 +    PRINT_STDOUT,
 +    PRINT_STDERR,
 +    USE_DEBUG,
 +    PRINT_LITERAL,
 +    WRITE_WITH_NEWLINE,
 +    WRITELN_EMPTY_STRING,
 +    WRITE_LITERAL
 +]);
 +
 +impl EarlyLintPass for Write {
 +    fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
++        if let ItemKind::Impl(box ImplKind {
++            of_trait: Some(trait_ref),
++            ..
++        }) = &item.kind
++        {
 +            let trait_name = trait_ref
 +                .path
 +                .segments
 +                .iter()
 +                .last()
 +                .expect("path has at least one segment")
 +                .ident
 +                .name;
 +            if trait_name == sym::Debug {
 +                self.in_debug_impl = true;
 +            }
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
 +        self.in_debug_impl = false;
 +    }
 +
 +    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
 +        fn is_build_script(cx: &EarlyContext<'_>) -> bool {
 +            // Cargo sets the crate name for build scripts to `build_script_build`
 +            cx.sess
 +                .opts
 +                .crate_name
 +                .as_ref()
 +                .map_or(false, |crate_name| crate_name == "build_script_build")
 +        }
 +
 +        if mac.path == sym!(print) {
 +            if !is_build_script(cx) {
 +                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
 +            }
 +            self.lint_print_with_newline(cx, mac);
 +        } else if mac.path == sym!(println) {
 +            if !is_build_script(cx) {
 +                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
 +            }
 +            self.lint_println_empty_string(cx, mac);
 +        } else if mac.path == sym!(eprint) {
 +            span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`");
 +            self.lint_print_with_newline(cx, mac);
 +        } else if mac.path == sym!(eprintln) {
 +            span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
 +            self.lint_println_empty_string(cx, mac);
 +        } else if mac.path == sym!(write) {
 +            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
 +                if check_newlines(&fmt_str) {
 +                    span_lint_and_then(
 +                        cx,
 +                        WRITE_WITH_NEWLINE,
 +                        mac.span(),
 +                        "using `write!()` with a format string that ends in a single newline",
 +                        |err| {
 +                            err.multipart_suggestion(
 +                                "use `writeln!()` instead",
 +                                vec![
 +                                    (mac.path.span, String::from("writeln")),
 +                                    (newline_span(&fmt_str), String::new()),
 +                                ],
 +                                Applicability::MachineApplicable,
 +                            );
 +                        },
 +                    )
 +                }
 +            }
 +        } else if mac.path == sym!(writeln) {
 +            if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
 +                if fmt_str.symbol == kw::Empty {
 +                    let mut applicability = Applicability::MachineApplicable;
 +                    // FIXME: remove this `#[allow(...)]` once the issue #5822 gets fixed
 +                    #[allow(clippy::option_if_let_else)]
 +                    let suggestion = if let Some(e) = expr {
 +                        snippet_with_applicability(cx, e.span, "v", &mut applicability)
 +                    } else {
 +                        applicability = Applicability::HasPlaceholders;
 +                        Cow::Borrowed("v")
 +                    };
 +
 +                    span_lint_and_sugg(
 +                        cx,
 +                        WRITELN_EMPTY_STRING,
 +                        mac.span(),
 +                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
 +                        "replace it with",
 +                        format!("writeln!({})", suggestion),
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Given a format string that ends in a newline and its span, calculates the span of the
 +/// newline, or the format string itself if the format string consists solely of a newline.
 +fn newline_span(fmtstr: &StrLit) -> Span {
 +    let sp = fmtstr.span;
 +    let contents = &fmtstr.symbol.as_str();
 +
 +    if *contents == r"\n" {
 +        return sp;
 +    }
 +
 +    let newline_sp_hi = sp.hi()
 +        - match fmtstr.style {
 +            StrStyle::Cooked => BytePos(1),
 +            StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
 +        };
 +
 +    let newline_sp_len = if contents.ends_with('\n') {
 +        BytePos(1)
 +    } else if contents.ends_with(r"\n") {
 +        BytePos(2)
 +    } else {
 +        panic!("expected format string to contain a newline");
 +    };
 +
 +    sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi)
 +}
 +
 +impl Write {
 +    /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
 +    /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
 +    /// the contents of the string, whether it's a raw string, and the span of the literal in the
 +    /// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
 +    /// `format_str` should be written to.
 +    ///
 +    /// Example:
 +    ///
 +    /// Calling this function on
 +    /// ```rust
 +    /// # use std::fmt::Write;
 +    /// # let mut buf = String::new();
 +    /// # let something = "something";
 +    /// writeln!(buf, "string to write: {}", something);
 +    /// ```
 +    /// will return
 +    /// ```rust,ignore
 +    /// (Some("string to write: {}"), Some(buf))
 +    /// ```
 +    #[allow(clippy::too_many_lines)]
 +    fn check_tts<'a>(
 +        &self,
 +        cx: &EarlyContext<'a>,
 +        tts: TokenStream,
 +        is_write: bool,
 +    ) -> (Option<StrLit>, Option<Expr>) {
 +        use rustc_parse_format::{
 +            AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied,
 +            FormatSpec, ParseMode, Parser, Piece,
 +        };
 +
 +        let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
 +        let mut expr: Option<Expr> = None;
 +        if is_write {
 +            expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
 +                Ok(p) => Some(p.into_inner()),
 +                Err(_) => return (None, None),
 +            };
 +            // might be `writeln!(foo)`
 +            if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
 +                return (None, expr);
 +            }
 +        }
 +
 +        let fmtstr = match parser.parse_str_lit() {
 +            Ok(fmtstr) => fmtstr,
 +            Err(_) => return (None, expr),
 +        };
 +        let tmp = fmtstr.symbol.as_str();
 +        let mut args = vec![];
 +        let mut fmt_parser = Parser::new(&tmp, None, None, false, ParseMode::Format);
 +        while let Some(piece) = fmt_parser.next() {
 +            if !fmt_parser.errors.is_empty() {
 +                return (None, expr);
 +            }
 +            if let Piece::NextArgument(arg) = piece {
 +                if !self.in_debug_impl && arg.format.ty == "?" {
 +                    // FIXME: modify rustc's fmt string parser to give us the current span
 +                    span_lint(
 +                        cx,
 +                        USE_DEBUG,
 +                        parser.prev_token.span,
 +                        "use of `Debug`-based formatting",
 +                    );
 +                }
 +                args.push(arg);
 +            }
 +        }
 +        let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
 +        let mut idx = 0;
 +        loop {
 +            const SIMPLE: FormatSpec<'_> = FormatSpec {
 +                fill: None,
 +                align: AlignUnknown,
 +                flags: 0,
 +                precision: CountImplied,
 +                precision_span: None,
 +                width: CountImplied,
 +                width_span: None,
 +                ty: "",
 +                ty_span: None,
 +            };
 +            if !parser.eat(&token::Comma) {
 +                return (Some(fmtstr), expr);
 +            }
 +            let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) {
 +                expr
 +            } else {
 +                return (Some(fmtstr), None);
 +            };
 +            match &token_expr.kind {
 +                ExprKind::Lit(lit)
 +                    if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) =>
 +                {
 +                    let mut all_simple = true;
 +                    let mut seen = false;
 +                    for arg in &args {
 +                        match arg.position {
 +                            ArgumentImplicitlyIs(n) | ArgumentIs(n) => {
 +                                if n == idx {
 +                                    all_simple &= arg.format == SIMPLE;
 +                                    seen = true;
 +                                }
 +                            }
 +                            ArgumentNamed(_) => {}
 +                        }
 +                    }
 +                    if all_simple && seen {
 +                        span_lint(cx, lint, token_expr.span, "literal with an empty format string");
 +                    }
 +                    idx += 1;
 +                }
 +                ExprKind::Assign(lhs, rhs, _) => {
 +                    if_chain! {
 +                        if let ExprKind::Lit(ref lit) = rhs.kind;
 +                        if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..));
 +                        if let ExprKind::Path(_, p) = &lhs.kind;
 +                        then {
 +                            let mut all_simple = true;
 +                            let mut seen = false;
 +                            for arg in &args {
 +                                match arg.position {
 +                                    ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
 +                                    ArgumentNamed(name) => {
 +                                        if *p == name {
 +                                            seen = true;
 +                                            all_simple &= arg.format == SIMPLE;
 +                                        }
 +                                    },
 +                                }
 +                            }
 +                            if all_simple && seen {
 +                                span_lint(cx, lint, rhs.span, "literal with an empty format string");
 +                            }
 +                        }
 +                    }
 +                }
 +                _ => idx += 1,
 +            }
 +        }
 +    }
 +
 +    fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
 +        if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
 +            if fmt_str.symbol == kw::Empty {
 +                let name = mac.path.segments[0].ident.name;
 +                span_lint_and_sugg(
 +                    cx,
 +                    PRINTLN_EMPTY_STRING,
 +                    mac.span(),
 +                    &format!("using `{}!(\"\")`", name),
 +                    "replace it with",
 +                    format!("{}!()", name),
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
 +        if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
 +            if check_newlines(&fmt_str) {
 +                let name = mac.path.segments[0].ident.name;
 +                let suggested = format!("{}ln", name);
 +                span_lint_and_then(
 +                    cx,
 +                    PRINT_WITH_NEWLINE,
 +                    mac.span(),
 +                    &format!(
 +                        "using `{}!()` with a format string that ends in a single newline",
 +                        name
 +                    ),
 +                    |err| {
 +                        err.multipart_suggestion(
 +                            &format!("use `{}!` instead", suggested),
 +                            vec![
 +                                (mac.path.span, suggested),
 +                                (newline_span(&fmt_str), String::new()),
 +                            ],
 +                            Applicability::MachineApplicable,
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Checks if the format string contains a single newline that terminates it.
 +///
 +/// Literal and escaped newlines are both checked (only literal for raw strings).
 +fn check_newlines(fmtstr: &StrLit) -> bool {
 +    let mut has_internal_newline = false;
 +    let mut last_was_cr = false;
 +    let mut should_lint = false;
 +
 +    let contents = &fmtstr.symbol.as_str();
 +
 +    let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
 +        let c = c.unwrap();
 +
 +        if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
 +            should_lint = true;
 +        } else {
 +            last_was_cr = c == '\r';
 +            if c == '\n' {
 +                has_internal_newline = true;
 +            }
 +        }
 +    };
 +
 +    match fmtstr.style {
 +        StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
 +        StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
 +    }
 +
 +    should_lint
 +}
index fd2a7d171d020aff7b99eb2826f199a6bd591287,0000000000000000000000000000000000000000..8fd1dea9aeef9bfe6843c7df2c35e0d45e49ec67
mode 100644,000000..100644
--- /dev/null
@@@ -1,646 -1,0 +1,646 @@@
-     Make sure that `clippy dev update_lints` added it beforehand. The configuration value is now 
-     cloned or copied into a local value that is then passed to the impl struct like this:
 +# Adding a new lint
 +
 +You are probably here because you want to add a new lint to Clippy. If this is
 +the first time you're contributing to Clippy, this document guides you through
 +creating an example lint from scratch.
 +
 +To get started, we will create a lint that detects functions called `foo`,
 +because that's clearly a non-descriptive name.
 +
 +- [Adding a new lint](#adding-a-new-lint)
 +  - [Setup](#setup)
 +  - [Getting Started](#getting-started)
 +  - [Testing](#testing)
 +  - [Rustfix tests](#rustfix-tests)
 +  - [Edition 2018 tests](#edition-2018-tests)
 +  - [Testing manually](#testing-manually)
 +  - [Lint declaration](#lint-declaration)
 +  - [Lint passes](#lint-passes)
 +  - [Emitting a lint](#emitting-a-lint)
 +  - [Adding the lint logic](#adding-the-lint-logic)
 +  - [Author lint](#author-lint)
 +  - [Documentation](#documentation)
 +  - [Running rustfmt](#running-rustfmt)
 +  - [Debugging](#debugging)
 +  - [PR Checklist](#pr-checklist)
 +  - [Adding configuration to a lint](#adding-configuration-to-a-lint)
 +  - [Cheatsheet](#cheatsheet)
 +
 +## Setup
 +
 +See the [Basics](basics.md#get-the-code) documentation.
 +
 +## Getting Started
 +
 +There is a bit of boilerplate code that needs to be set up when creating a new
 +lint. Fortunately, you can use the clippy dev tools to handle this for you. We
 +are naming our new lint `foo_functions` (lints are generally written in snake
 +case), and we don't need type information so it will have an early pass type
 +(more on this later on). If you're not sure if the name you chose fits the lint,
 +take a look at our [lint naming guidelines][lint_naming]. To get started on this
 +lint you can run `cargo dev new_lint --name=foo_functions --pass=early
 +--category=pedantic` (category will default to nursery if not provided). This
 +command will create two files: `tests/ui/foo_functions.rs` and
 +`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
 +register the new lint. For cargo lints, two project hierarchies (fail/pass) will
 +be created by default under `tests/ui-cargo`.
 +
 +Next, we'll open up these files and add our lint!
 +
 +## Testing
 +
 +Let's write some tests first that we can execute while we iterate on our lint.
 +
 +Clippy uses UI tests for testing. UI tests check that the output of Clippy is
 +exactly as expected. Each test is just a plain Rust file that contains the code
 +we want to check. The output of Clippy is compared against a `.stderr` file.
 +Note that you don't have to create this file yourself, we'll get to
 +generating the `.stderr` files further down.
 +
 +We start by opening the test file created at `tests/ui/foo_functions.rs`.
 +
 +Update the file with some examples to get started:
 +
 +```rust
 +#![warn(clippy::foo_functions)]
 +
 +// Impl methods
 +struct A;
 +impl A {
 +    pub fn fo(&self) {}
 +    pub fn foo(&self) {}
 +    pub fn food(&self) {}
 +}
 +
 +// Default trait methods
 +trait B {
 +    fn fo(&self) {}
 +    fn foo(&self) {}
 +    fn food(&self) {}
 +}
 +
 +// Plain functions
 +fn fo() {}
 +fn foo() {}
 +fn food() {}
 +
 +fn main() {
 +    // We also don't want to lint method calls
 +    foo();
 +    let a = A;
 +    a.foo();
 +}
 +```
 +
 +Now we can run the test with `TESTNAME=foo_functions cargo uitest`,
 +currently this test is meaningless though.
 +
 +While we are working on implementing our lint, we can keep running the UI
 +test. That allows us to check if the output is turning into what we want.
 +
 +Once we are satisfied with the output, we need to run
 +`cargo dev bless` to update the `.stderr` file for our lint.
 +Please note that, we should run `TESTNAME=foo_functions cargo uitest`
 +every time before running `cargo dev bless`.
 +Running `TESTNAME=foo_functions cargo uitest` should pass then. When we commit
 +our lint, we need to commit the generated `.stderr` files, too. In general, you
 +should only commit files changed by `cargo dev bless` for the
 +specific lint you are creating/editing. Note that if the generated files are
 +empty, they should be removed.
 +
 +### Cargo lints
 +
 +For cargo lints, the process of testing differs in that we are interested in
 +the `Cargo.toml` manifest file. We also need a minimal crate associated
 +with that manifest.
 +
 +If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint`
 +we will find by default two new crates, each with its manifest file:
 +
 +* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error.
 +* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger the lint.
 +
 +If you need more cases, you can copy one of those crates (under `foo_categories`) and rename it.
 +
 +The process of generating the `.stderr` file is the same, and prepending the `TESTNAME`
 +variable to `cargo uitest` works too.
 +
 +## Rustfix tests
 +
 +If the lint you are working on is making use of structured suggestions, the
 +test file should include a `// run-rustfix` comment at the top. This will
 +additionally run [rustfix] for that test. Rustfix will apply the suggestions
 +from the lint to the code of the test file and compare that to the contents of
 +a `.fixed` file.
 +
 +Use `cargo dev bless` to automatically generate the
 +`.fixed` file after running the tests.
 +
 +[rustfix]: https://github.com/rust-lang/rustfix
 +
 +## Edition 2018 tests
 +
 +Some features require the 2018 edition to work (e.g. `async_await`), but
 +compile-test tests run on the 2015 edition by default. To change this behavior
 +add `// edition:2018` at the top of the test file (note that it's space-sensitive).
 +
 +## Testing manually
 +
 +Manually testing against an example file can be useful if you have added some
 +`println!`s and the test suite output becomes unreadable. To try Clippy with
 +your local modifications, run
 +
 +```
 +env __CLIPPY_INTERNAL_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs
 +```
 +
 +from the working copy root. With tests in place, let's have a look at
 +implementing our lint now.
 +
 +## Lint declaration
 +
 +Let's start by opening the new file created in the `clippy_lints` crate
 +at `clippy_lints/src/foo_functions.rs`. That's the crate where all the
 +lint code is. This file has already imported some initial things we will need:
 +
 +```rust
 +use rustc_lint::{EarlyLintPass, EarlyContext};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_ast::ast::*;
 +```
 +
 +The next step is to update the lint declaration. Lints are declared using the
 +[`declare_clippy_lint!`][declare_clippy_lint] macro, and we just need to update
 +the auto-generated lint declaration to have a real description, something like this:
 +
 +```rust
 +declare_clippy_lint! {
 +    /// **What it does:**
 +    ///
 +    /// **Why is this bad?**
 +    ///
 +    /// **Known problems:** None.
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust
 +    /// // example code
 +    /// ```
 +    pub FOO_FUNCTIONS,
 +    pedantic,
 +    "function named `foo`, which is not a descriptive name"
 +}
 +```
 +
 +* The section of lines prefixed with `///` constitutes the lint documentation
 +  section. This is the default documentation style and will be displayed
 +  [like this][example_lint_page]. To render and open this documentation locally
 +  in a browser, run `cargo dev serve`.
 +* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
 +  [lint naming guidelines][lint_naming] here when naming your lint.
 +  In short, the name should state the thing that is being checked for and
 +  read well when used with `allow`/`warn`/`deny`.
 +* `pedantic` sets the lint level to `Allow`.
 +  The exact mapping can be found [here][category_level_mapping]
 +* The last part should be a text that explains what exactly is wrong with the
 +  code
 +
 +The rest of this file contains an empty implementation for our lint pass,
 +which in this case is `EarlyLintPass` and should look like this:
 +
 +```rust
 +// clippy_lints/src/foo_functions.rs
 +
 +// .. imports and lint declaration ..
 +
 +declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
 +
 +impl EarlyLintPass for FooFunctions {}
 +```
 +
 +Normally after declaring the lint, we have to run `cargo dev update_lints`,
 +which updates some files, so Clippy knows about the new lint. Since we used
 +`cargo dev new_lint ...` to generate the lint declaration, this was done
 +automatically. While `update_lints` automates most of the things, it doesn't
 +automate everything. We will have to register our lint pass manually in the
 +`register_plugins` function in `clippy_lints/src/lib.rs`:
 +
 +```rust
 +store.register_early_pass(|| box foo_functions::FooFunctions);
 +```
 +
 +As one may expect, there is a corresponding `register_late_pass` method
 +available as well. Without a call to one of `register_early_pass` or
 +`register_late_pass`, the lint pass in question will not be run.
 +
 +One reason that `cargo dev` does not automate this step is that multiple lints
 +can use the same lint pass, so registering the lint pass may already be done
 +when adding a new lint. Another reason that this step is not automated is that
 +the order that the passes are registered determines the order the passes
 +actually run, which in turn affects the order that any emitted lints are output
 +in.
 +
 +[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
 +[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
 +
 +## Lint passes
 +
 +Writing a lint that only checks for the name of a function means that we only
 +have to deal with the AST and don't have to deal with the type system at all.
 +This is good, because it makes writing this particular lint less complicated.
 +
 +We have to make this decision with every new Clippy lint. It boils down to using
 +either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
 +
 +In short, the `LateLintPass` has access to type information while the
 +`EarlyLintPass` doesn't. If you don't need access to type information, use the
 +`EarlyLintPass`. The `EarlyLintPass` is also faster. However linting speed
 +hasn't really been a concern with Clippy so far.
 +
 +Since we don't need type information for checking the function name, we used
 +`--pass=early` when running the new lint automation and all the imports were
 +added accordingly.
 +
 +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
 +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
 +
 +## Emitting a lint
 +
 +With UI tests and the lint declaration in place, we can start working on the
 +implementation of the lint logic.
 +
 +Let's start by implementing the `EarlyLintPass` for our `FooFunctions`:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        // TODO: Emit lint here
 +    }
 +}
 +```
 +
 +We implement the [`check_fn`][check_fn] method from the
 +[`EarlyLintPass`][early_lint_pass] trait. This gives us access to various
 +information about the function that is currently being checked. More on that in
 +the next section. Let's worry about the details later and emit our lint for
 +*every* function definition first.
 +
 +Depending on how complex we want our lint message to be, we can choose from a
 +variety of lint emission functions. They can all be found in
 +[`clippy_lints/src/utils/diagnostics.rs`][diagnostics].
 +
 +`span_lint_and_help` seems most appropriate in this case. It allows us to
 +provide an extra help message and we can't really suggest a better name
 +automatically. This is how it looks:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        span_lint_and_help(
 +            cx,
 +            FOO_FUNCTIONS,
 +            span,
 +            "function named `foo`",
 +            None,
 +            "consider using a more meaningful name"
 +        );
 +    }
 +}
 +```
 +
 +Running our UI test should now produce output that contains the lint message.
 +
 +According to [the rustc-dev-guide], the text should be matter of fact and avoid
 +capitalization and periods, unless multiple sentences are needed.
 +When code or an identifier must appear in a message or label, it should be
 +surrounded with single grave accents \`.
 +
 +[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
 +[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
 +[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html
 +
 +## Adding the lint logic
 +
 +Writing the logic for your lint will most likely be different from our example,
 +so this section is kept rather short.
 +
 +Using the [`check_fn`][check_fn] method gives us access to [`FnKind`][fn_kind]
 +that has the [`FnKind::Fn`] variant. It provides access to the name of the
 +function/method via an [`Ident`][ident].
 +
 +With that we can expand our `check_fn` method to:
 +
 +```rust
 +impl EarlyLintPass for FooFunctions {
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
 +        if is_foo_fn(fn_kind) {
 +            span_lint_and_help(
 +                cx,
 +                FOO_FUNCTIONS,
 +                span,
 +                "function named `foo`",
 +                None,
 +                "consider using a more meaningful name"
 +            );
 +        }
 +    }
 +}
 +```
 +
 +We separate the lint conditional from the lint emissions because it makes the
 +code a bit easier to read. In some cases this separation would also allow to
 +write some unit tests (as opposed to only UI tests) for the separate function.
 +
 +In our example, `is_foo_fn` looks like:
 +
 +```rust
 +// use statements, impl EarlyLintPass, check_fn, ..
 +
 +fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
 +    match fn_kind {
 +        FnKind::Fn(_, ident, ..) => {
 +            // check if `fn` name is `foo`
 +            ident.name.as_str() == "foo"
 +        }
 +        // ignore closures
 +        FnKind::Closure(..) => false
 +    }
 +}
 +```
 +
 +Now we should also run the full test suite with `cargo test`. At this point
 +running `cargo test` should produce the expected output. Remember to run
 +`cargo dev bless` to update the `.stderr` file.
 +
 +`cargo test` (as opposed to `cargo uitest`) will also ensure that our lint
 +implementation is not violating any Clippy lints itself.
 +
 +That should be it for the lint implementation. Running `cargo test` should now
 +pass.
 +
 +[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html
 +[`FnKind::Fn`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/visit/enum.FnKind.html#variant.Fn
 +[ident]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Ident.html
 +
 +## Specifying the lint's minimum supported Rust version (msrv)
 +
 +Projects supporting older versions of Rust would need to disable a lint if it targets features
 +present in later versions. Support for this can be added by specifying an msrv in your lint like so,
 +
 +```rust
 +const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0);
 +```
 +
 +The project's msrv will also have to be an attribute in the lint so you'll have to add a struct
 +and constructor for your lint. The project's msrv needs to be passed when the lint is registered
 +in `lib.rs`
 +
 +```rust
 +pub struct ManualStrip {
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl ManualStrip {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self { msrv }
 +    }
 +}
 +```
 +
 +The project's msrv can then be matched against the lint's msrv in the LintPass using the `meets_msrv` utility
 +function.
 +
 +``` rust
 +if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
 +    return;
 +}
 +```
 +
 +The project's msrv can also be specified as an inner attribute, which overrides the value from
 +`clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing
 +LateContext/EarlyContext.
 +
 +```rust
 +impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        ...
 +    }
 +    extract_msrv_attr!(LateContext);
 +}
 +```
 +
 +Once the msrv is added to the lint, a relevant test case should be added to `tests/ui/min_rust_version_attr.rs`
 +which verifies that the lint isn't emitted if the project's msrv is lower.
 +
 +## Author lint
 +
 +If you have trouble implementing your lint, there is also the internal `author`
 +lint to generate Clippy code that detects the offending pattern. It does not
 +work for all of the Rust syntax, but can give a good starting point.
 +
 +The quickest way to use it, is the
 +[Rust playground: play.rust-lang.org][author_example].
 +Put the code you want to lint into the editor and add the `#[clippy::author]`
 +attribute above the item. Then run Clippy via `Tools -> Clippy` and you should
 +see the generated code in the output below.
 +
 +[Here][author_example] is an example on the playground.
 +
 +If the command was executed successfully, you can copy the code over to where
 +you are implementing your lint.
 +
 +[author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
 +
 +## Documentation
 +
 +The final thing before submitting our PR is to add some documentation to our
 +lint declaration.
 +
 +Please document your lint with a doc comment akin to the following:
 +
 +```rust
 +declare_clippy_lint! {
 +    /// **What it does:** Checks for ... (describe what the lint matches).
 +    ///
 +    /// **Why is this bad?** Supply the reason for linting the code.
 +    ///
 +    /// **Known problems:** None. (Or describe where it could go wrong.)
 +    ///
 +    /// **Example:**
 +    ///
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// Insert a short example of code that triggers the lint
 +    ///
 +    /// // Good
 +    /// Insert a short example of improved code that doesn't trigger the lint
 +    /// ```
 +    pub FOO_FUNCTIONS,
 +    pedantic,
 +    "function named `foo`, which is not a descriptive name"
 +}
 +```
 +
 +Once your lint is merged, this documentation will show up in the [lint
 +list][lint_list].
 +
 +[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
 +
 +## Running rustfmt
 +
 +[Rustfmt] is a tool for formatting Rust code according to style guidelines.
 +Your code has to be formatted by `rustfmt` before a PR can be merged.
 +Clippy uses nightly `rustfmt` in the CI.
 +
 +It can be installed via `rustup`:
 +
 +```bash
 +rustup component add rustfmt --toolchain=nightly
 +```
 +
 +Use `cargo dev fmt` to format the whole codebase. Make sure that `rustfmt` is
 +installed for the nightly toolchain.
 +
 +[Rustfmt]: https://github.com/rust-lang/rustfmt
 +
 +## Debugging
 +
 +If you want to debug parts of your lint implementation, you can use the [`dbg!`]
 +macro anywhere in your code. Running the tests should then include the debug
 +output in the `stdout` part.
 +
 +[`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
 +
 +## PR Checklist
 +
 +Before submitting your PR make sure you followed all of the basic requirements:
 +
 +<!-- Sync this with `.github/PULL_REQUEST_TEMPLATE` -->
 +
 +- \[ ] Followed [lint naming conventions][lint_naming]
 +- \[ ] Added passing UI tests (including committed `.stderr` file)
 +- \[ ] `cargo test` passes locally
 +- \[ ] Executed `cargo dev update_lints`
 +- \[ ] Added lint documentation
 +- \[ ] Run `cargo dev fmt`
 +
 +## Adding configuration to a lint
 +
 +Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace 
 +directory. Adding a configuration to a lint can be useful for thresholds or to constrain some
 +behavior that can be seen as a false positive for some users. Adding a configuration is done 
 +in the following steps:
 +
 +1. Adding a new configuration entry to [clippy_lints::utils::conf](/clippy_lints/src/utils/conf.rs)
 +    like this:
 +    ```rust
 +    /// Lint: LINT_NAME. <The configuration field doc comment>
 +    (configuration_ident, "configuration_value": Type, DefaultValue),
 +    ```
 +    The configuration value and identifier should usually be the same. The doc comment will be 
 +    automatically added to the lint documentation.
 +2. Adding the configuration value to the lint impl struct:
 +    1. This first requires the definition of a lint impl struct. Lint impl structs are usually 
 +        generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
 +        to add some kind of metadata to it:
 +        ```rust
 +        // Generated struct definition
 +        declare_lint_pass!(StructName => [
 +            LINT_NAME
 +        ]);
 +
 +        // New manual definition struct
 +        #[derive(Copy, Clone)]
 +        pub struct StructName {}
 +
 +        impl_lint_pass!(StructName => [
 +            LINT_NAME
 +        ]);
 +        ```
 +    
 +    2. Next add the configuration value and a corresponding creation method like this:
 +        ```rust
 +        #[derive(Copy, Clone)]
 +        pub struct StructName {
 +            configuration_ident: Type,
 +        }
 +
 +        // ...
 +
 +        impl StructName {
 +            pub fn new(configuration_ident: Type) -> Self {
 +                Self {
 +                    configuration_ident,
 +                }
 +            }
 +        }
 +        ```
 +3. Passing the configuration value to the lint impl struct:
 +
 +    First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs). 
-     store.register_late_pass(|| box module::StructName);
++    The configuration value is now cloned or copied into a local value that is then passed to the
++    impl struct like this:
 +    ```rust
 +    // Default generated registration:
-     store.register_late_pass(move || box module::StructName::new(configuration_ident));
++    store.register_*_pass(|| box module::StructName);
 +
 +    // New registration with configuration value
 +    let configuration_ident = conf.configuration_ident.clone();
-         with the configuration value and a rust file that should be linted by clippy. The test can 
++    store.register_*_pass(move || box module::StructName::new(configuration_ident));
 +    ```
 +
 +    Congratulations the work is almost done. The configuration value can now be accessed
 +    in the linting code via `self.configuration_ident`.
 +
 +4. Adding tests:
 +    1. The default configured value can be tested like any normal lint in [`tests/ui`](/tests/ui).
 +    2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml). 
 +        Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file 
++        with the configuration value and a rust file that should be linted by Clippy. The test can 
 +        otherwise be written as usual.
 +
 +## Cheatsheet
 +
 +Here are some pointers to things you are likely going to need for every lint:
 +
 +* [Clippy utils][utils] - Various helper functions. Maybe the function you need
 +  is already in here (`implements_trait`, `match_path`, `snippet`, etc)
 +* [Clippy diagnostics][diagnostics]
 +* [The `if_chain` macro][if_chain]
 +* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]
 +* [`Span`][span]
 +* [`Applicability`][applicability]
 +* [Common tools for writing lints](common_tools_writing_lints.md) helps with common operations
 +* [The rustc-dev-guide][rustc-dev-guide] explains a lot of internal compiler concepts
 +* [The nightly rustc docs][nightly_docs] which has been linked to throughout
 +  this guide
 +
 +For `EarlyLintPass` lints:
 +
 +* [`EarlyLintPass`][early_lint_pass]
 +* [`rustc_ast::ast`][ast]
 +
 +For `LateLintPass` lints:
 +
 +* [`LateLintPass`][late_lint_pass]
 +* [`Ty::TyKind`][ty]
 +
 +While most of Clippy's lint utils are documented, most of rustc's internals lack
 +documentation currently. This is unfortunate, but in most cases you can probably
 +get away with copying things from existing similar lints. If you are stuck,
 +don't hesitate to ask on [Zulip] or in the issue/PR.
 +
 +[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
 +[if_chain]: https://docs.rs/if_chain/*/if_chain/
 +[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
 +[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
 +[span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
 +[applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
 +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
 +[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/
 +[ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html
 +[ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/index.html
 +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
index 57f83bdf32bc2bb748a72f6cacf7d7017d59e09d,0000000000000000000000000000000000000000..a9416f3b20b7a3b229c4a5c1b62ba1451f60bf26
mode 100644,000000..100644
--- /dev/null
@@@ -1,116 -1,0 +1,116 @@@
- This is a concise list of abbreviations that can come up during clippy development. An extensive
 +# Basics for hacking on Clippy
 +
 +This document explains the basics for hacking on Clippy. Besides others, this
 +includes how to build and test Clippy. For a more in depth description on
 +the codebase take a look at [Adding Lints] or [Common Tools].
 +
 +[Adding Lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md
 +
 +- [Basics for hacking on Clippy](#basics-for-hacking-on-clippy)
 +  - [Get the Code](#get-the-code)
 +  - [Building and Testing](#building-and-testing)
 +  - [`cargo dev`](#cargo-dev)
 +  - [Common Abbreviations](#common-abbreviations)
 +  - [PR](#pr)
 +
 +## Get the Code
 +
 +First, make sure you have checked out the latest version of Clippy. If this is
 +your first time working on Clippy, create a fork of the repository and clone it
 +afterwards with the following command:
 +
 +```bash
 +git clone git@github.com:<your-username>/rust-clippy
 +```
 +
 +If you've already cloned Clippy in the past, update it to the latest version:
 +
 +```bash
 +# upstream has to be the remote of the rust-lang/rust-clippy repo
 +git fetch upstream
 +# make sure that you are on the master branch
 +git checkout master
 +# rebase your master branch on the upstream master
 +git rebase upstream/master
 +# push to the master branch of your fork
 +git push
 +```
 +
 +## Building and Testing
 +
 +You can build and test Clippy like every other Rust project:
 +
 +```bash
 +cargo build  # builds Clippy
 +cargo test   # tests Clippy
 +```
 +
 +Since Clippy's test suite is pretty big, there are some commands that only run a
 +subset of Clippy's tests:
 +
 +```bash
 +# only run UI tests
 +cargo uitest
 +# only run UI tests starting with `test_`
 +TESTNAME="test_" cargo uitest
 +# only run dogfood tests
 +cargo test --test dogfood
 +```
 +
 +If the output of a [UI test] differs from the expected output, you can update the
 +reference file with:
 +
 +```bash
 +cargo dev bless
 +```
 +
 +For example, this is necessary, if you fix a typo in an error message of a lint
 +or if you modify a test file to add a test case.
 +
 +_Note:_ This command may update more files than you intended. In that case only
 +commit the files you wanted to update.
 +
 +[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#guide-to-the-ui-tests
 +
 +## `cargo dev`
 +
 +Clippy has some dev tools to make working on Clippy more convenient. These tools
 +can be accessed through the `cargo dev` command. Available tools are listed
 +below. To get more information about these commands, just call them with
 +`--help`.
 +
 +```bash
 +# formats the whole Clippy codebase and all tests
 +cargo dev fmt
 +# register or update lint names/groups/...
 +cargo dev update_lints
 +# create a new lint and register it
 +cargo dev new_lint
 +# (experimental) Setup Clippy to work with rust-analyzer
 +cargo dev ra_setup
 +```
 +
 +## PR
 +
 +We follow a rustc no merge-commit policy.
 +See <https://rustc-dev-guide.rust-lang.org/contributing.html#opening-a-pr>.
 +
 +## Common Abbreviations
 +
 +| Abbreviation | Meaning                                |
 +| ------------ | -------------------------------------- |
 +| UB           | Undefined Behavior                     |
 +| FP           | False Positive                         |
 +| FN           | False Negative                         |
 +| ICE          | Internal Compiler Error                |
 +| AST          | Abstract Syntax Tree                   |
 +| MIR          | Mid-Level Intermediate Representation  |
 +| HIR          | High-Level Intermediate Representation |
 +| TCX          | Type context                           |
 +
++This is a concise list of abbreviations that can come up during Clippy development. An extensive
 +general list can be found in the [rustc-dev-guide glossary][glossary]. Always feel free to ask if
 +an abbreviation or meaning is unclear to you.
 +
 +[glossary]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html
index ba946563ec595d1624fb5a6515a11e4d2fcb1233,0000000000000000000000000000000000000000..2b793589049ba7b7d16dffb9156115d2cdd52ced
mode 100644,000000..100644
--- /dev/null
@@@ -1,26 -1,0 +1,29 @@@
 +#![feature(proc_macro_quote)]
 +#![deny(rust_2018_idioms)]
 +// FIXME: Remove this attribute once the weird failure is gone.
 +#![allow(unused_extern_crates)]
 +extern crate proc_macro;
 +
 +use proc_macro::{quote, TokenStream};
 +
 +#[proc_macro_derive(ClippyMiniMacroTest)]
++/// # Panics
++///
++/// Panics if the macro derivation fails
 +pub fn mini_macro(_: TokenStream) -> TokenStream {
 +    quote!(
 +        #[allow(unused)]
 +        fn needless_take_by_value(s: String) {
 +            println!("{}", s.len());
 +        }
 +        #[allow(unused)]
 +        fn needless_loop(items: &[u8]) {
 +            for i in 0..items.len() {
 +                println!("{}", items[i]);
 +            }
 +        }
 +        fn line_wrapper() {
 +            println!("{}", line!());
 +        }
 +    )
 +}
index f55d55d706587d299ae2a111a6b5ff2e6d3bed25,0000000000000000000000000000000000000000..b617203bef6d8208dac6f963f5df95bafa421a88
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-01-30"
 +[toolchain]
++channel = "nightly-2021-02-03"
 +components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ef932f367b101a61e47375f0b580482a42ab4e2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,95 @@@
++#![warn(clippy::missing_panics_doc)]
++#![allow(clippy::option_map_unit_fn)]
++
++fn main() {}
++
++/// This needs to be documented
++pub fn unwrap() {
++    let result = Err("Hi");
++    result.unwrap()
++}
++
++/// This needs to be documented
++pub fn panic() {
++    panic!("This function panics")
++}
++
++/// This needs to be documented
++pub fn todo() {
++    todo!()
++}
++
++/// This needs to be documented
++pub fn inner_body(opt: Option<u32>) {
++    opt.map(|x| {
++        if x == 10 {
++            panic!()
++        }
++    });
++}
++
++/// This is documented
++///
++/// # Panics
++///
++/// Panics if `result` if an error
++pub fn unwrap_documented() {
++    let result = Err("Hi");
++    result.unwrap()
++}
++
++/// This is documented
++///
++/// # Panics
++///
++/// Panics just because
++pub fn panic_documented() {
++    panic!("This function panics")
++}
++
++/// This is documented
++///
++/// # Panics
++///
++/// Panics if `opt` is Just(10)
++pub fn inner_body_documented(opt: Option<u32>) {
++    opt.map(|x| {
++        if x == 10 {
++            panic!()
++        }
++    });
++}
++
++/// This is documented
++///
++/// # Panics
++///
++/// We still need to do this part
++pub fn todo_documented() {
++    todo!()
++}
++
++/// This is okay because it is private
++fn unwrap_private() {
++    let result = Err("Hi");
++    result.unwrap()
++}
++
++/// This is okay because it is private
++fn panic_private() {
++    panic!("This function panics")
++}
++
++/// This is okay because it is private
++fn todo_private() {
++    todo!()
++}
++
++/// This is okay because it is private
++fn inner_body_private(opt: Option<u32>) {
++    opt.map(|x| {
++        if x == 10 {
++            panic!()
++        }
++    });
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c0c4e9e4fa7eec6d682eddd4f7b214cfeded6712
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,67 @@@
++error: docs for function which may panic missing `# Panics` section
++  --> $DIR/doc_panics.rs:7:1
++   |
++LL | / pub fn unwrap() {
++LL | |     let result = Err("Hi");
++LL | |     result.unwrap()
++LL | | }
++   | |_^
++   |
++   = note: `-D clippy::missing-panics-doc` implied by `-D warnings`
++note: first possible panic found here
++  --> $DIR/doc_panics.rs:9:5
++   |
++LL |     result.unwrap()
++   |     ^^^^^^^^^^^^^^^
++
++error: docs for function which may panic missing `# Panics` section
++  --> $DIR/doc_panics.rs:13:1
++   |
++LL | / pub fn panic() {
++LL | |     panic!("This function panics")
++LL | | }
++   | |_^
++   |
++note: first possible panic found here
++  --> $DIR/doc_panics.rs:14:5
++   |
++LL |     panic!("This function panics")
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: docs for function which may panic missing `# Panics` section
++  --> $DIR/doc_panics.rs:18:1
++   |
++LL | / pub fn todo() {
++LL | |     todo!()
++LL | | }
++   | |_^
++   |
++note: first possible panic found here
++  --> $DIR/doc_panics.rs:19:5
++   |
++LL |     todo!()
++   |     ^^^^^^^
++   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: docs for function which may panic missing `# Panics` section
++  --> $DIR/doc_panics.rs:23:1
++   |
++LL | / pub fn inner_body(opt: Option<u32>) {
++LL | |     opt.map(|x| {
++LL | |         if x == 10 {
++LL | |             panic!()
++LL | |         }
++LL | |     });
++LL | | }
++   | |_^
++   |
++note: first possible panic found here
++  --> $DIR/doc_panics.rs:26:13
++   |
++LL |             panic!()
++   |             ^^^^^^^^
++   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: aborting due to 4 previous errors
++
index 8174a0175ab3228f02036746e97306fff403050a,0000000000000000000000000000000000000000..c209f5b4b7278c2ac7590673c11ffc5e4a5fca02
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,91 @@@
-         foo: u8,
-         bar: String,
 +// run-rustfix
 +
 +#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 +#![allow(unused)]
 +
 +fn main() {
 +    // nop
 +}
 +
 +pub mod enums {
 +    #[non_exhaustive]
 +    pub enum Exhaustive {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    /// Some docs
 +    #[repr(C)]
 +    #[non_exhaustive]
 +    pub enum ExhaustiveWithAttrs {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, already non_exhaustive
 +    #[non_exhaustive]
 +    pub enum NonExhaustive {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, private
 +    enum ExhaustivePrivate {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, private
 +    #[non_exhaustive]
 +    enum NonExhaustivePrivate {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +}
 +
 +pub mod structs {
 +    #[non_exhaustive]
 +    pub struct Exhaustive {
-         foo: u8,
++        pub foo: u8,
++        pub bar: String,
 +    }
 +
 +    // no warning, already non_exhaustive
 +    #[non_exhaustive]
 +    pub struct NonExhaustive {
-         foo: u8,
-         bar: String,
++        pub foo: u8,
++        pub bar: String,
++    }
++
++    // no warning, private fields
++    pub struct ExhaustivePrivateFieldTuple(u8);
++
++    // no warning, private fields
++    pub struct ExhaustivePrivateField {
++        pub foo: u8,
 +        bar: String,
 +    }
 +
 +    // no warning, private
 +    struct ExhaustivePrivate {
-         foo: u8,
-         bar: String,
++        pub foo: u8,
++        pub bar: String,
 +    }
 +
 +    // no warning, private
 +    #[non_exhaustive]
 +    struct NonExhaustivePrivate {
++        pub foo: u8,
++        pub bar: String,
 +    }
 +}
index b476f09f8a0872178c1874b549c8bd3f18bedc20,0000000000000000000000000000000000000000..6f59dbf2da59b126f0537c2b034193e076ca1164
mode 100644,000000..100644
--- /dev/null
@@@ -1,79 -1,0 +1,88 @@@
-         foo: u8,
-         bar: String,
 +// run-rustfix
 +
 +#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 +#![allow(unused)]
 +
 +fn main() {
 +    // nop
 +}
 +
 +pub mod enums {
 +    pub enum Exhaustive {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    /// Some docs
 +    #[repr(C)]
 +    pub enum ExhaustiveWithAttrs {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, already non_exhaustive
 +    #[non_exhaustive]
 +    pub enum NonExhaustive {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, private
 +    enum ExhaustivePrivate {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +
 +    // no warning, private
 +    #[non_exhaustive]
 +    enum NonExhaustivePrivate {
 +        Foo,
 +        Bar,
 +        Baz,
 +        Quux(String),
 +    }
 +}
 +
 +pub mod structs {
 +    pub struct Exhaustive {
-         foo: u8,
++        pub foo: u8,
++        pub bar: String,
 +    }
 +
 +    // no warning, already non_exhaustive
 +    #[non_exhaustive]
 +    pub struct NonExhaustive {
-         foo: u8,
-         bar: String,
++        pub foo: u8,
++        pub bar: String,
++    }
++
++    // no warning, private fields
++    pub struct ExhaustivePrivateFieldTuple(u8);
++
++    // no warning, private fields
++    pub struct ExhaustivePrivateField {
++        pub foo: u8,
 +        bar: String,
 +    }
 +
 +    // no warning, private
 +    struct ExhaustivePrivate {
-         foo: u8,
-         bar: String,
++        pub foo: u8,
++        pub bar: String,
 +    }
 +
 +    // no warning, private
 +    #[non_exhaustive]
 +    struct NonExhaustivePrivate {
++        pub foo: u8,
++        pub bar: String,
 +    }
 +}
index 7369fe75a4f7408ade55119d57f141e8ac5b2e3c,0000000000000000000000000000000000000000..8fbab535a9b25a67ca26b7b9edeabb9550a7ead2
mode 100644,000000..100644
--- /dev/null
@@@ -1,61 -1,0 +1,61 @@@
- LL | |         foo: u8,
- LL | |         bar: String,
 +error: exported enums should not be exhaustive
 +  --> $DIR/exhaustive_items.rs:11:5
 +   |
 +LL | /     pub enum Exhaustive {
 +LL | |         Foo,
 +LL | |         Bar,
 +LL | |         Baz,
 +LL | |         Quux(String),
 +LL | |     }
 +   | |_____^
 +   |
 +note: the lint level is defined here
 +  --> $DIR/exhaustive_items.rs:3:9
 +   |
 +LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 +help: try adding #[non_exhaustive]
 +   |
 +LL |     #[non_exhaustive]
 +LL |     pub enum Exhaustive {
 +   |
 +
 +error: exported enums should not be exhaustive
 +  --> $DIR/exhaustive_items.rs:20:5
 +   |
 +LL | /     pub enum ExhaustiveWithAttrs {
 +LL | |         Foo,
 +LL | |         Bar,
 +LL | |         Baz,
 +LL | |         Quux(String),
 +LL | |     }
 +   | |_____^
 +   |
 +help: try adding #[non_exhaustive]
 +   |
 +LL |     #[non_exhaustive]
 +LL |     pub enum ExhaustiveWithAttrs {
 +   |
 +
 +error: exported structs should not be exhaustive
 +  --> $DIR/exhaustive_items.rs:55:5
 +   |
 +LL | /     pub struct Exhaustive {
++LL | |         pub foo: u8,
++LL | |         pub bar: String,
 +LL | |     }
 +   | |_____^
 +   |
 +note: the lint level is defined here
 +  --> $DIR/exhaustive_items.rs:3:35
 +   |
 +LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
 +   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +help: try adding #[non_exhaustive]
 +   |
 +LL |     #[non_exhaustive]
 +LL |     pub struct Exhaustive {
 +   |
 +
 +error: aborting due to 3 previous errors
 +
index 73e550b3df891864fac7c2cd2a46920efbf890f9,0000000000000000000000000000000000000000..e3561863c1e1ff7f00f1e52703e808cdb1c64e63
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,169 @@@
-         impl Foo<'_> {
 +#![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 fe878e5f20601ff68d80908aaf95711f52463d9e,0000000000000000000000000000000000000000..a6941dabeb88d56a722fa07b7efbcf620c395cea
mode 100644,000000..100644
--- /dev/null
@@@ -1,45 -1,0 +1,45 @@@
-   --> $DIR/let_and_return.rs:154:13
 +error: returning the result of a `let` binding from a block
 +  --> $DIR/let_and_return.rs:7:5
 +   |
 +LL |     let x = 5;
 +   |     ---------- unnecessary `let` binding
 +LL |     x
 +   |     ^
 +   |
 +   = note: `-D clippy::let-and-return` implied by `-D warnings`
 +help: return the expression directly
 +   |
 +LL |     
 +LL |     5
 +   |
 +
 +error: returning the result of a `let` binding from a block
 +  --> $DIR/let_and_return.rs:13:9
 +   |
 +LL |         let x = 5;
 +   |         ---------- unnecessary `let` binding
 +LL |         x
 +   |         ^
 +   |
 +help: return the expression directly
 +   |
 +LL |         
 +LL |         5
 +   |
 +
 +error: returning the result of a `let` binding from a block
++  --> $DIR/let_and_return.rs:164:13
 +   |
 +LL |             let clone = Arc::clone(&self.foo);
 +   |             ---------------------------------- unnecessary `let` binding
 +LL |             clone
 +   |             ^^^^^
 +   |
 +help: return the expression directly
 +   |
 +LL |             
 +LL |             Arc::clone(&self.foo) as _
 +   |
 +
 +error: aborting due to 3 previous errors
 +
index 97789bb766f891027817d4c65204c23377adef18,0000000000000000000000000000000000000000..44c51e8112a7d6fdf4322d3cc3328bacc15c7665
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,112 @@@
 +#![feature(exclusive_range_pattern)]
 +#![feature(half_open_range_patterns)]
 +#![warn(clippy::match_overlapping_arm)]
 +#![allow(clippy::redundant_pattern_matching)]
 +
 +/// Tests for match_overlapping_arm
 +
 +fn overlapping() {
 +    const FOO: u64 = 2;
 +
 +    match 42 {
 +        0..=10 => println!("0 ... 10"),
 +        0..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..=5 => println!("0 ... 5"),
 +        6..=7 => println!("6 ... 7"),
 +        FOO..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..=5 => println!("0 ... 5"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..=2 => println!("0 ... 2"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..=10 => println!("0 ... 10"),
 +        11..=50 => println!("11 ... 50"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        2 => println!("2"),
 +        0..2 => println!("0 .. 2"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..10 => println!("0 .. 10"),
 +        10..50 => println!("10 .. 50"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..11 => println!("0 .. 11"),
 +        0..=11 => println!("0 ... 11"),
 +        _ => (),
 +    }
 +
++    match 42 {
++        5..7 => println!("5 .. 7"),
++        0..10 => println!("0 .. 10"),
++        _ => (),
++    }
++
++    match 42 {
++        5..10 => println!("5 .. 10"),
++        0..=10 => println!("0 ... 10"),
++        _ => (),
++    }
++
++    match 42 {
++        0..14 => println!("0 .. 14"),
++        5..10 => println!("5 .. 10"),
++        _ => (),
++    }
++
++    match 42 {
++        5..14 => println!("5 .. 14"),
++        0..=10 => println!("0 ... 10"),
++        _ => (),
++    }
++
++    match 42 {
++        0..7 => println!("0 .. 7"),
++        0..=10 => println!("0 ... 10"),
++        _ => (),
++    }
++
 +    /*
 +    // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
 +    match 42 {
 +        0.. => println!("0 .. 42"),
 +        3.. => println!("3 .. 42"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        ..=23 => println!("0 ... 23"),
 +        ..26 => println!("0 .. 26"),
 +        _ => (),
 +    }
 +    */
 +
 +    if let None = Some(42) {
 +        // nothing
 +    } else if let None = Some(42) {
 +        // another nothing :-)
 +    }
 +}
 +
 +fn main() {}
index eb20d5405a95e984b19ab2712f13362e28b800a9,0000000000000000000000000000000000000000..f25a66d634e888189565a0bbec8e1b8c9994be03
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,63 @@@
-   --> $DIR/match_overlapping_arm.rs:26:9
 +error: some ranges overlap
 +  --> $DIR/match_overlapping_arm.rs:12:9
 +   |
 +LL |         0..=10 => println!("0 ... 10"),
 +   |         ^^^^^^
 +   |
 +   = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
 +note: overlaps with this
 +  --> $DIR/match_overlapping_arm.rs:13:9
 +   |
 +LL |         0..=11 => println!("0 ... 11"),
 +   |         ^^^^^^
 +
 +error: some ranges overlap
 +  --> $DIR/match_overlapping_arm.rs:18:9
 +   |
 +LL |         0..=5 => println!("0 ... 5"),
 +   |         ^^^^^
 +   |
 +note: overlaps with this
 +  --> $DIR/match_overlapping_arm.rs:20:9
 +   |
 +LL |         FOO..=11 => println!("0 ... 11"),
 +   |         ^^^^^^^^
 +
 +error: some ranges overlap
- LL |         0..=5 => println!("0 ... 5"),
++  --> $DIR/match_overlapping_arm.rs:55:9
 +   |
-   --> $DIR/match_overlapping_arm.rs:25:9
++LL |         0..11 => println!("0 .. 11"),
 +   |         ^^^^^
 +   |
 +note: overlaps with this
- LL |         2 => println!("2"),
-    |         ^
++  --> $DIR/match_overlapping_arm.rs:56:9
 +   |
-   --> $DIR/match_overlapping_arm.rs:32:9
++LL |         0..=11 => println!("0 ... 11"),
++   |         ^^^^^^
 +
 +error: some ranges overlap
- LL |         0..=2 => println!("0 ... 2"),
-    |         ^^^^^
++  --> $DIR/match_overlapping_arm.rs:80:9
 +   |
-   --> $DIR/match_overlapping_arm.rs:31:9
++LL |         0..=10 => println!("0 ... 10"),
++   |         ^^^^^^
 +   |
 +note: overlaps with this
- LL |         2 => println!("2"),
-    |         ^
++  --> $DIR/match_overlapping_arm.rs:79:9
 +   |
-   --> $DIR/match_overlapping_arm.rs:55:9
++LL |         5..14 => println!("5 .. 14"),
++   |         ^^^^^
 +
 +error: some ranges overlap
- LL |         0..11 => println!("0 .. 11"),
-    |         ^^^^^
++  --> $DIR/match_overlapping_arm.rs:85:9
 +   |
-   --> $DIR/match_overlapping_arm.rs:56:9
++LL |         0..7 => println!("0 .. 7"),
++   |         ^^^^
 +   |
 +note: overlaps with this
- LL |         0..=11 => println!("0 ... 11"),
++  --> $DIR/match_overlapping_arm.rs:86:9
 +   |
++LL |         0..=10 => println!("0 ... 10"),
 +   |         ^^^^^^
 +
 +error: aborting due to 5 previous errors
 +
index 6c5ffe6aba8b7b7c1e4923c957617f6df31ffc64,0000000000000000000000000000000000000000..a7f8f54f2be04cb98667127b87d3db75c50e1301
mode 100644,000000..100644
--- /dev/null
@@@ -1,83 -1,0 +1,84 @@@
-     clippy::wrong_self_convention
 +// edition:2018
 +
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::missing_errors_doc,
 +    clippy::needless_pass_by_value,
 +    clippy::must_use_candidate,
 +    clippy::unused_self,
 +    clippy::needless_lifetimes,
 +    clippy::missing_safety_doc,
++    clippy::wrong_self_convention,
++    clippy::missing_panics_doc
 +)]
 +
 +use std::ops::Mul;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +fn main() {}
 +
 +pub struct T1;
 +impl T1 {
 +    // corner cases: should not lint
 +
 +    // no error, not public interface
 +    pub(crate) fn drop(&mut self) {}
 +
 +    // no error, private function
 +    fn neg(self) -> Self {
 +        self
 +    }
 +
 +    // no error, private function
 +    fn eq(&self, other: Self) -> bool {
 +        true
 +    }
 +
 +    // No error; self is a ref.
 +    fn sub(&self, other: Self) -> &Self {
 +        self
 +    }
 +
 +    // No error; different number of arguments.
 +    fn div(self) -> Self {
 +        self
 +    }
 +
 +    // No error; wrong return type.
 +    fn rem(self, other: Self) {}
 +
 +    // Fine
 +    fn into_u32(self) -> u32 {
 +        0
 +    }
 +
 +    fn into_u16(&self) -> u16 {
 +        0
 +    }
 +
 +    fn to_something(self) -> u32 {
 +        0
 +    }
 +
 +    fn new(self) -> Self {
 +        unimplemented!();
 +    }
 +
 +    pub fn next<'b>(&'b mut self) -> Option<&'b mut T1> {
 +        unimplemented!();
 +    }
 +}
 +
 +pub struct T2;
 +impl T2 {
 +    // Shouldn't trigger lint as it is unsafe.
 +    pub unsafe fn add(self, rhs: Self) -> Self {
 +        self
 +    }
 +
 +    // Should not trigger lint since this is an async function.
 +    pub async fn next(&mut self) -> Option<Self> {
 +        None
 +    }
 +}
index f8d248fc98d82a2db4ac7ae5d106bfe10d7fe782,0000000000000000000000000000000000000000..69a3390b03b0b2cac0988e1f35dc1796e0bcd41d
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,88 @@@
-     clippy::wrong_self_convention
 +// edition:2018
 +
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::missing_errors_doc,
 +    clippy::needless_pass_by_value,
 +    clippy::must_use_candidate,
 +    clippy::unused_self,
 +    clippy::needless_lifetimes,
 +    clippy::missing_safety_doc,
++    clippy::wrong_self_convention,
++    clippy::missing_panics_doc
 +)]
 +
 +use std::ops::Mul;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +fn main() {}
 +pub struct T;
 +
 +impl T {
 +    // *****************************************
 +    // trait method list part 1, should lint all
 +    // *****************************************
 +    pub fn add(self, other: T) -> T {
 +        unimplemented!()
 +    }
 +
 +    pub fn as_mut(&mut self) -> &mut T {
 +        unimplemented!()
 +    }
 +
 +    pub fn as_ref(&self) -> &T {
 +        unimplemented!()
 +    }
 +
 +    pub fn bitand(self, rhs: T) -> T {
 +        unimplemented!()
 +    }
 +
 +    pub fn bitor(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn bitxor(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn borrow(&self) -> &str {
 +        unimplemented!()
 +    }
 +
 +    pub fn borrow_mut(&mut self) -> &mut str {
 +        unimplemented!()
 +    }
 +
 +    pub fn clone(&self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn cmp(&self, other: &Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn default() -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn deref(&self) -> &Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn deref_mut(&mut self) -> &mut Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn div(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn drop(&mut self) {
 +        unimplemented!()
 +    }
 +    // **********
 +    // part 1 end
 +    // **********
 +}
index 2b7d4628c3fa02b703e9a58cb98b73d4a1dd6489,0000000000000000000000000000000000000000..86c63946516ce84453725eff5a31b58cb1ac246c
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,143 @@@
-   --> $DIR/method_list_1.rs:25:5
 +error: method `add` can be confused for the standard trait method `std::ops::Add::add`
-   --> $DIR/method_list_1.rs:29:5
++  --> $DIR/method_list_1.rs:26:5
 +   |
 +LL | /     pub fn add(self, other: T) -> T {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
 +   = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
 +
 +error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
-   --> $DIR/method_list_1.rs:33:5
++  --> $DIR/method_list_1.rs:30:5
 +   |
 +LL | /     pub fn as_mut(&mut self) -> &mut T {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
 +
 +error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
-   --> $DIR/method_list_1.rs:37:5
++  --> $DIR/method_list_1.rs:34:5
 +   |
 +LL | /     pub fn as_ref(&self) -> &T {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
 +
 +error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
-   --> $DIR/method_list_1.rs:41:5
++  --> $DIR/method_list_1.rs:38:5
 +   |
 +LL | /     pub fn bitand(self, rhs: T) -> T {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
 +
 +error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
-   --> $DIR/method_list_1.rs:45:5
++  --> $DIR/method_list_1.rs:42:5
 +   |
 +LL | /     pub fn bitor(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
 +
 +error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
-   --> $DIR/method_list_1.rs:49:5
++  --> $DIR/method_list_1.rs:46:5
 +   |
 +LL | /     pub fn bitxor(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
 +
 +error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
-   --> $DIR/method_list_1.rs:53:5
++  --> $DIR/method_list_1.rs:50:5
 +   |
 +LL | /     pub fn borrow(&self) -> &str {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
 +
 +error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
-   --> $DIR/method_list_1.rs:57:5
++  --> $DIR/method_list_1.rs:54:5
 +   |
 +LL | /     pub fn borrow_mut(&mut self) -> &mut str {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
 +
 +error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
-   --> $DIR/method_list_1.rs:61:5
++  --> $DIR/method_list_1.rs:58:5
 +   |
 +LL | /     pub fn clone(&self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
 +
 +error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
-   --> $DIR/method_list_1.rs:69:5
++  --> $DIR/method_list_1.rs:62:5
 +   |
 +LL | /     pub fn cmp(&self, other: &Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
 +
 +error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
-   --> $DIR/method_list_1.rs:73:5
++  --> $DIR/method_list_1.rs:70:5
 +   |
 +LL | /     pub fn deref(&self) -> &Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
 +
 +error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
-   --> $DIR/method_list_1.rs:77:5
++  --> $DIR/method_list_1.rs:74:5
 +   |
 +LL | /     pub fn deref_mut(&mut self) -> &mut Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
 +
 +error: method `div` can be confused for the standard trait method `std::ops::Div::div`
-   --> $DIR/method_list_1.rs:81:5
++  --> $DIR/method_list_1.rs:78:5
 +   |
 +LL | /     pub fn div(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
 +
 +error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
++  --> $DIR/method_list_1.rs:82:5
 +   |
 +LL | /     pub fn drop(&mut self) {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
 +
 +error: aborting due to 14 previous errors
 +
index ed5e0d384bf5040c0d90135bc6cd65ab5832306d,0000000000000000000000000000000000000000..2cdc1a06fe689dab34e495eee9466253e7836c8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,89 @@@
-     clippy::wrong_self_convention
 +// edition:2018
 +
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::missing_errors_doc,
 +    clippy::needless_pass_by_value,
 +    clippy::must_use_candidate,
 +    clippy::unused_self,
 +    clippy::needless_lifetimes,
 +    clippy::missing_safety_doc,
++    clippy::wrong_self_convention,
++    clippy::missing_panics_doc
 +)]
 +
 +use std::ops::Mul;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +fn main() {}
 +pub struct T;
 +
 +impl T {
 +    // *****************************************
 +    // trait method list part 2, should lint all
 +    // *****************************************
 +
 +    pub fn eq(&self, other: &Self) -> bool {
 +        unimplemented!()
 +    }
 +
 +    pub fn from_iter<T>(iter: T) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn from_str(s: &str) -> Result<Self, Self> {
 +        unimplemented!()
 +    }
 +
 +    pub fn hash(&self, state: &mut T) {
 +        unimplemented!()
 +    }
 +
 +    pub fn index(&self, index: usize) -> &Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn index_mut(&mut self, index: usize) -> &mut Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn into_iter(self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn mul(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn neg(self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn next(&mut self) -> Option<Self> {
 +        unimplemented!()
 +    }
 +
 +    pub fn not(self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn rem(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn shl(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn shr(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +
 +    pub fn sub(self, rhs: Self) -> Self {
 +        unimplemented!()
 +    }
 +    // **********
 +    // part 2 end
 +    // **********
 +}
index b6fd435695698e6ca47adee8a423824472e6b14d,0000000000000000000000000000000000000000..0142e2991081c79ae4099788ea6c85ed02535428
mode 100644,000000..100644
--- /dev/null
@@@ -1,153 -1,0 +1,153 @@@
-   --> $DIR/method_list_2.rs:26:5
 +error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
-   --> $DIR/method_list_2.rs:30:5
++  --> $DIR/method_list_2.rs:27:5
 +   |
 +LL | /     pub fn eq(&self, other: &Self) -> bool {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
 +   = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
 +
 +error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
-   --> $DIR/method_list_2.rs:34:5
++  --> $DIR/method_list_2.rs:31:5
 +   |
 +LL | /     pub fn from_iter<T>(iter: T) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
 +
 +error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
-   --> $DIR/method_list_2.rs:38:5
++  --> $DIR/method_list_2.rs:35:5
 +   |
 +LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
 +
 +error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
-   --> $DIR/method_list_2.rs:42:5
++  --> $DIR/method_list_2.rs:39:5
 +   |
 +LL | /     pub fn hash(&self, state: &mut T) {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
 +
 +error: method `index` can be confused for the standard trait method `std::ops::Index::index`
-   --> $DIR/method_list_2.rs:46:5
++  --> $DIR/method_list_2.rs:43:5
 +   |
 +LL | /     pub fn index(&self, index: usize) -> &Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
 +
 +error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
-   --> $DIR/method_list_2.rs:50:5
++  --> $DIR/method_list_2.rs:47:5
 +   |
 +LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
 +
 +error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
-   --> $DIR/method_list_2.rs:54:5
++  --> $DIR/method_list_2.rs:51:5
 +   |
 +LL | /     pub fn into_iter(self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
 +
 +error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
-   --> $DIR/method_list_2.rs:58:5
++  --> $DIR/method_list_2.rs:55:5
 +   |
 +LL | /     pub fn mul(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
 +
 +error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
-   --> $DIR/method_list_2.rs:62:5
++  --> $DIR/method_list_2.rs:59:5
 +   |
 +LL | /     pub fn neg(self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
 +
 +error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
-   --> $DIR/method_list_2.rs:66:5
++  --> $DIR/method_list_2.rs:63:5
 +   |
 +LL | /     pub fn next(&mut self) -> Option<Self> {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
 +
 +error: method `not` can be confused for the standard trait method `std::ops::Not::not`
-   --> $DIR/method_list_2.rs:70:5
++  --> $DIR/method_list_2.rs:67:5
 +   |
 +LL | /     pub fn not(self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
 +
 +error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
-   --> $DIR/method_list_2.rs:74:5
++  --> $DIR/method_list_2.rs:71:5
 +   |
 +LL | /     pub fn rem(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
 +
 +error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
-   --> $DIR/method_list_2.rs:78:5
++  --> $DIR/method_list_2.rs:75:5
 +   |
 +LL | /     pub fn shl(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
 +
 +error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
-   --> $DIR/method_list_2.rs:82:5
++  --> $DIR/method_list_2.rs:79:5
 +   |
 +LL | /     pub fn shr(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
 +
 +error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
++  --> $DIR/method_list_2.rs:83:5
 +   |
 +LL | /     pub fn sub(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
 +
 +error: aborting due to 15 previous errors
 +